<?php

declare(strict_types=1);

namespace App\Support\Filament;

use App\Models\AlertDelivery;
use App\Models\Finding;
use App\Models\FindingException;
use App\Support\Audit\AuditActionId;
use App\Support\Audit\AuditActorType;
use App\Support\Audit\AuditOutcome;
use App\Support\Badges\BadgeCatalog;
use App\Support\Badges\BadgeDomain;
use App\Support\Baselines\BaselineProfileStatus;
use App\Support\Findings\FindingOutcomeSemantics;
use App\Support\Inventory\InventoryPolicyTypeMeta;
use App\Support\OperationCatalog;
use App\Support\RestoreRunStatus;
use Illuminate\Support\Str;

final class FilterOptionCatalog
{
    /**
     * @return array<string, string>
     */
    public static function auditActorTypes(): array
    {
        return self::badgeOptions(BadgeDomain::AuditActorType, array_map(
            static fn (AuditActorType $type): string => $type->value,
            AuditActorType::cases(),
        ));
    }

    /**
     * @param  iterable<mixed>|null  $actions
     * @return array<string, string>
     */
    public static function auditActions(?iterable $actions = null): array
    {
        return collect($actions ?? AuditActionId::knownValues())
            ->filter(fn (mixed $action): bool => is_string($action) && trim($action) !== '')
            ->map(fn (string $action): string => trim($action))
            ->unique()
            ->sort()
            ->mapWithKeys(fn (string $action): array => [$action => AuditActionId::labelFor($action)])
            ->all();
    }

    /**
     * @return array<string, string>
     */
    public static function auditOutcomes(): array
    {
        return self::badgeOptions(BadgeDomain::AuditOutcome, array_map(
            static fn (AuditOutcome $outcome): string => $outcome->value,
            AuditOutcome::cases(),
        ));
    }

    /**
     * @param  iterable<mixed>|null  $types
     * @return array<string, string>
     */
    public static function auditTargetTypes(?iterable $types = null): array
    {
        return collect($types ?? [])
            ->filter(fn (mixed $type): bool => is_string($type) && trim($type) !== '')
            ->map(fn (string $type): string => trim($type))
            ->unique()
            ->sort()
            ->mapWithKeys(fn (string $type): array => [$type => str_replace('_', ' ', ucfirst($type))])
            ->all();
    }

    /**
     * @return array<string, string>
     */
    public static function alertDeliveryStatuses(): array
    {
        return self::badgeOptions(BadgeDomain::AlertDeliveryStatus, [
            AlertDelivery::STATUS_QUEUED,
            AlertDelivery::STATUS_DEFERRED,
            AlertDelivery::STATUS_SENT,
            AlertDelivery::STATUS_FAILED,
            AlertDelivery::STATUS_SUPPRESSED,
            AlertDelivery::STATUS_CANCELED,
        ]);
    }

    /**
     * @return array<string, string>
     */
    public static function baselineProfileStatuses(): array
    {
        return collect(BaselineProfileStatus::cases())
            ->mapWithKeys(fn (BaselineProfileStatus $status): array => [
                $status->value => $status->label(),
            ])
            ->all();
    }

    /**
     * @return array<string, string>
     */
    public static function findingStatuses(): array
    {
        return self::badgeOptions(BadgeDomain::FindingStatus, [
            Finding::STATUS_NEW,
            Finding::STATUS_TRIAGED,
            Finding::STATUS_IN_PROGRESS,
            Finding::STATUS_REOPENED,
            Finding::STATUS_RESOLVED,
            Finding::STATUS_CLOSED,
            Finding::STATUS_RISK_ACCEPTED,
        ]);
    }

    /**
     * @return array<string, string>
     */
    public static function findingWorkflowFamilies(): array
    {
        return [
            'active' => 'Active workflow',
            'accepted_risk' => 'Accepted risk',
            'historical' => 'Historical',
        ];
    }

    /**
     * @return array<string, string>
     */
    public static function findingTerminalOutcomes(): array
    {
        return app(FindingOutcomeSemantics::class)->terminalOutcomeOptions();
    }

    /**
     * @return array<string, string>
     */
    public static function findingVerificationStates(): array
    {
        return app(FindingOutcomeSemantics::class)->verificationStateOptions();
    }

    /**
     * @return array<string, string>
     */
    public static function findingSeverities(): array
    {
        return self::badgeOptions(BadgeDomain::FindingSeverity, [
            Finding::SEVERITY_LOW,
            Finding::SEVERITY_MEDIUM,
            Finding::SEVERITY_HIGH,
            Finding::SEVERITY_CRITICAL,
        ]);
    }

    /**
     * @return array<string, string>
     */
    public static function findingExceptionStatuses(): array
    {
        return self::badgeOptions(BadgeDomain::FindingExceptionStatus, [
            FindingException::STATUS_PENDING,
            FindingException::STATUS_ACTIVE,
            FindingException::STATUS_EXPIRING,
            FindingException::STATUS_EXPIRED,
            FindingException::STATUS_REJECTED,
            FindingException::STATUS_REVOKED,
            FindingException::STATUS_SUPERSEDED,
        ]);
    }

    /**
     * @return array<string, string>
     */
    public static function findingExceptionValidityStates(): array
    {
        return self::badgeOptions(BadgeDomain::FindingRiskGovernanceValidity, [
            FindingException::VALIDITY_VALID,
            FindingException::VALIDITY_EXPIRING,
            FindingException::VALIDITY_EXPIRED,
            FindingException::VALIDITY_REVOKED,
            FindingException::VALIDITY_REJECTED,
            FindingException::VALIDITY_MISSING_SUPPORT,
        ]);
    }

    /**
     * @return array<string, string>
     */
    public static function findingGovernanceAttentionStates(): array
    {
        return [
            'healthy' => 'Healthy governance',
            'attention_needed' => 'Governance attention needed',
        ];
    }

    /**
     * @param  iterable<mixed>|null  $types
     * @return array<string, string>
     */
    public static function operationTypes(?iterable $types = null): array
    {
        return OperationCatalog::filterOptions($types);
    }

    /**
     * @param  iterable<mixed>|null  $types
     * @return array<string, string>
     */
    public static function policyTypes(?iterable $types = null): array
    {
        $values = $types === null
            ? collect(InventoryPolicyTypeMeta::all())->pluck('type')
            : collect($types);

        return $values
            ->filter(fn (mixed $type): bool => is_string($type) && trim($type) !== '')
            ->map(fn (string $type): string => trim($type))
            ->unique()
            ->mapWithKeys(function (string $type): array {
                $label = InventoryPolicyTypeMeta::metaFor($type)['label'] ?? null;

                return [$type => is_string($label) && $label !== '' ? $label : $type];
            })
            ->sort()
            ->all();
    }

    /**
     * @param  iterable<mixed>|null  $platforms
     * @return array<string, string>
     */
    public static function platforms(?iterable $platforms = null): array
    {
        $values = collect($platforms ?? [])
            ->merge(collect(InventoryPolicyTypeMeta::all())->pluck('platform'))
            ->merge(['all', 'android', 'ios', 'iOS', 'ipadOS', 'macOS', 'macos', 'mobile', 'windows', 'windows10', 'windows11'])
            ->filter(fn (mixed $platform): bool => is_string($platform) && trim($platform) !== '')
            ->map(fn (string $platform): string => trim($platform))
            ->unique()
            ->sort()
            ->values();

        return $values
            ->mapWithKeys(fn (string $platform): array => [$platform => self::platformLabel($platform)])
            ->sort()
            ->all();
    }

    /**
     * @return array<string, string>
     */
    public static function restoreRunOutcomes(): array
    {
        return [
            'succeeded' => BadgeCatalog::spec(BadgeDomain::RestoreRunStatus, RestoreRunStatus::Completed->value)->label,
            'partial' => BadgeCatalog::spec(BadgeDomain::RestoreRunStatus, RestoreRunStatus::Partial->value)->label,
            'failed' => BadgeCatalog::spec(BadgeDomain::RestoreRunStatus, RestoreRunStatus::Failed->value)->label,
        ];
    }

    /**
     * @return array<string, string>
     */
    public static function restoreRunStatuses(): array
    {
        return self::badgeOptions(BadgeDomain::RestoreRunStatus, [
            RestoreRunStatus::Draft->value,
            RestoreRunStatus::Scoped->value,
            RestoreRunStatus::Checked->value,
            RestoreRunStatus::Previewed->value,
            RestoreRunStatus::Pending->value,
            RestoreRunStatus::Queued->value,
            RestoreRunStatus::Running->value,
            RestoreRunStatus::Completed->value,
            RestoreRunStatus::Partial->value,
            RestoreRunStatus::Failed->value,
            RestoreRunStatus::Cancelled->value,
            RestoreRunStatus::Aborted->value,
            RestoreRunStatus::CompletedWithErrors->value,
        ]);
    }

    /**
     * @param  array<int, string>  $values
     * @return array<string, string>
     */
    private static function badgeOptions(BadgeDomain $domain, array $values): array
    {
        return collect($values)
            ->mapWithKeys(fn (string $value): array => [$value => BadgeCatalog::spec($domain, $value)->label])
            ->all();
    }

    private static function platformLabel(string $platform): string
    {
        return match (Str::of($platform)
            ->trim()
            ->lower()
            ->replace(['_', '-'], '')
            ->toString()) {
            'windows', 'windows10', 'windows11' => 'Windows',
            'ios', 'ipados' => 'iOS',
            'macos' => 'macOS',
            default => InventoryPolicyTypeMeta::all()
                ? (string) \App\Support\Badges\TagBadgeCatalog::spec(\App\Support\Badges\TagBadgeDomain::Platform, $platform)->label
                : $platform,
        };
    }
}
