<?php

namespace App\Models;

use App\Support\Concerns\DerivesWorkspaceIdFromTenant;
use App\Support\Concerns\InteractsWithODataTypes;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;

class Policy extends Model
{
    use DerivesWorkspaceIdFromTenant;
    use HasFactory;
    use InteractsWithODataTypes;

    public const VISIBILITY_ACTIVE = 'active';

    public const VISIBILITY_IGNORED_LOCALLY = 'ignored_locally';

    public const VISIBILITY_PROVIDER_MISSING = 'provider_missing';

    public const VISIBILITY_IGNORED_LOCALLY_PROVIDER_MISSING = 'ignored_locally_provider_missing';

    protected $guarded = [];

    protected $casts = [
        'metadata' => 'array',
        'last_synced_at' => 'datetime',
        'ignored_at' => 'datetime',
        'missing_from_provider_at' => 'datetime',
    ];

    public function tenant(): BelongsTo
    {
        return $this->belongsTo(ManagedEnvironment::class, 'managed_environment_id');
    }

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

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

    public function scopeActive(Builder $query): Builder
    {
        return $query
            ->whereNull('ignored_at')
            ->whereNull('missing_from_provider_at');
    }

    public function scopeIgnored(Builder $query): Builder
    {
        return $query->whereNotNull('ignored_at');
    }

    public function scopeProviderMissing(Builder $query): Builder
    {
        return $query->whereNotNull('missing_from_provider_at');
    }

    public function scopeCurrentBackupEligible(Builder $query): Builder
    {
        return $query
            ->whereNull('ignored_at')
            ->whereNull('missing_from_provider_at');
    }

    public function isIgnoredLocally(): bool
    {
        return $this->ignored_at !== null;
    }

    public function isProviderMissing(): bool
    {
        return $this->missing_from_provider_at !== null;
    }

    public function visibilityState(): string
    {
        return match (true) {
            $this->isIgnoredLocally() && $this->isProviderMissing() => self::VISIBILITY_IGNORED_LOCALLY_PROVIDER_MISSING,
            $this->isIgnoredLocally() => self::VISIBILITY_IGNORED_LOCALLY,
            $this->isProviderMissing() => self::VISIBILITY_PROVIDER_MISSING,
            default => self::VISIBILITY_ACTIVE,
        };
    }

    public function isCurrentBackupEligible(): bool
    {
        return ! $this->isIgnoredLocally() && ! $this->isProviderMissing();
    }

    public function currentBackupBlockedReason(): ?string
    {
        if ($this->isProviderMissing()) {
            return self::VISIBILITY_PROVIDER_MISSING;
        }

        if ($this->isIgnoredLocally()) {
            return self::VISIBILITY_IGNORED_LOCALLY;
        }

        return null;
    }

    public function currentBackupBlockedReasonLabel(): ?string
    {
        return match ($this->currentBackupBlockedReason()) {
            self::VISIBILITY_PROVIDER_MISSING => 'Provider missing - current provider-backed capture is unavailable.',
            self::VISIBILITY_IGNORED_LOCALLY => 'Ignored locally - restore local visibility before fresh capture.',
            default => null,
        };
    }

    public function ignore(): void
    {
        $this->update(['ignored_at' => now()]);
    }

    public function unignore(): void
    {
        $this->update(['ignored_at' => null]);
    }
}
