<?php

declare(strict_types=1);

namespace App\Models;

use App\Support\Baselines\BaselineCaptureMode;
use App\Support\Baselines\BaselineProfileStatus;
use App\Support\Baselines\BaselineScope;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use JsonException;

class BaselineProfile extends Model
{
    use HasFactory;

    /**
     * @deprecated Use BaselineProfileStatus::Draft instead.
     */
    public const string STATUS_DRAFT = 'draft';

    /**
     * @deprecated Use BaselineProfileStatus::Active instead.
     */
    public const string STATUS_ACTIVE = 'active';

    /**
     * @deprecated Use BaselineProfileStatus::Archived instead.
     */
    public const string STATUS_ARCHIVED = 'archived';

    /** @var list<string> */
    protected $fillable = [
        'workspace_id',
        'name',
        'description',
        'version_label',
        'status',
        'capture_mode',
        'scope_jsonb',
        'active_snapshot_id',
        'created_by_user_id',
    ];

    /**
     * @return array<string, mixed>
     */
    protected function casts(): array
    {
        return [
            'status' => BaselineProfileStatus::class,
            'capture_mode' => BaselineCaptureMode::class,
        ];
    }

    protected function scopeJsonb(): Attribute
    {
        return Attribute::make(
            get: function (mixed $value): array {
                return BaselineScope::fromJsonb(
                    $this->decodeScopeJsonb($value)
                )->toJsonb();
            },
            set: function (mixed $value): string {
                $scope = BaselineScope::fromJsonb(is_array($value) ? $value : null)->toJsonb();

                try {
                    return json_encode($scope, JSON_THROW_ON_ERROR);
                } catch (JsonException) {
                    return '{"policy_types":[],"foundation_types":[]}';
                }
            },
        );
    }

    /**
     * Decode raw scope_jsonb value from the database.
     *
     * @return array<string, mixed>|null
     */
    private function decodeScopeJsonb(mixed $value): ?array
    {
        if (is_array($value)) {
            return $value;
        }

        if (is_string($value) && $value !== '') {
            try {
                $decoded = json_decode($value, true, flags: JSON_THROW_ON_ERROR);

                return is_array($decoded) ? $decoded : null;
            } catch (JsonException) {
                return null;
            }
        }

        return null;
    }

    public function workspace(): BelongsTo
    {
        return $this->belongsTo(Workspace::class);
    }

    public function createdByUser(): BelongsTo
    {
        return $this->belongsTo(User::class, 'created_by_user_id');
    }

    public function activeSnapshot(): BelongsTo
    {
        return $this->belongsTo(BaselineSnapshot::class, 'active_snapshot_id');
    }

    public function snapshots(): HasMany
    {
        return $this->hasMany(BaselineSnapshot::class);
    }

    public function tenantAssignments(): HasMany
    {
        return $this->hasMany(BaselineTenantAssignment::class);
    }
}
