<?php

namespace App\Models;

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

class BackupItem extends Model
{
    use DerivesWorkspaceIdFromTenant;
    use HasFactory;
    use InteractsWithODataTypes;
    use SoftDeletes;

    protected $guarded = [];

    protected $casts = [
        'payload' => 'array',
        'metadata' => 'array',
        'assignments' => 'array',
        'captured_at' => 'datetime',
    ];

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

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

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

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

    // Assignment helpers
    public function getAssignmentCountAttribute(): int
    {
        return count($this->assignments ?? []);
    }

    public function hasAssignments(): bool
    {
        return ! empty($this->assignments);
    }

    public function getGroupIdsAttribute(): array
    {
        return collect($this->assignments ?? [])
            ->pluck('target.groupId')
            ->filter()
            ->unique()
            ->values()
            ->toArray();
    }

    public function getScopeTagIdsAttribute(): array
    {
        return $this->metadata['scope_tag_ids'] ?? ['0'];
    }

    public function getScopeTagNamesAttribute(): array
    {
        return $this->metadata['scope_tag_names'] ?? ['Default'];
    }

    public function hasOrphanedAssignments(): bool
    {
        return $this->metadata['has_orphaned_assignments'] ?? false;
    }

    public function assignmentsFetchFailed(): bool
    {
        return $this->metadata['assignments_fetch_failed'] ?? false;
    }

    public function assignmentCaptureReason(): ?string
    {
        $reason = $this->metadata['assignment_capture_reason'] ?? null;

        return is_string($reason) && trim($reason) !== ''
            ? trim($reason)
            : null;
    }

    public function snapshotSource(): ?string
    {
        $source = $this->metadata['snapshot_source']
            ?? $this->metadata['source']
            ?? null;

        return is_string($source) && trim($source) !== ''
            ? trim($source)
            : null;
    }

    /**
     * @return list<string>
     */
    public function warningMessages(): array
    {
        $warnings = $this->metadata['warnings'] ?? [];

        if (! is_array($warnings)) {
            return [];
        }

        return collect($warnings)
            ->filter(fn (mixed $warning): bool => is_string($warning) && trim($warning) !== '')
            ->map(fn (string $warning): string => trim($warning))
            ->values()
            ->all();
    }

    public function integrityWarning(): ?string
    {
        $warning = $this->metadata['integrity_warning'] ?? null;

        return is_string($warning) && trim($warning) !== ''
            ? trim($warning)
            : null;
    }

    public function protectedPathsCount(): int
    {
        return max(0, (int) ($this->metadata['protected_paths_count'] ?? 0));
    }

    public function hasCapturedPayload(): bool
    {
        return is_array($this->payload) && $this->payload !== [];
    }

    public function isFoundation(): bool
    {
        $types = array_column(config('tenantpilot.foundation_types', []), 'type');

        return in_array($this->policy_type, $types, true);
    }

    public function resolvedDisplayName(): string
    {
        $metadata = $this->metadata ?? [];
        $payload = is_array($this->payload) ? $this->payload : [];
        $versionSnapshot = is_array($this->policyVersion?->snapshot) ? $this->policyVersion->snapshot : [];
        $name = $metadata['displayName']
            ?? $metadata['display_name']
            ?? $payload['displayName']
            ?? $payload['name']
            ?? $versionSnapshot['displayName']
            ?? $versionSnapshot['name']
            ?? $this->policy?->display_name
            ?? null;

        if (is_string($name) && $name !== '') {
            return $name;
        }

        return $this->policy_identifier;
    }

    // Scopes
    public function scopeWithAssignments($query)
    {
        return $query->whereNotNull('assignments')
            ->whereRaw('json_array_length(assignments) > 0');
    }
}
