<?php

declare(strict_types=1);

namespace App\Support\Tenants;

use App\Models\ManagedEnvironment;
use BackedEnum;
use Stringable;

enum TenantLifecycle: string
{
    case Draft = 'draft';
    case Onboarding = 'onboarding';
    case Active = 'active';
    case Archived = 'archived';

    /**
     * @return list<string>
     */
    public static function values(): array
    {
        return array_map(
            static fn (self $lifecycle): string => $lifecycle->value,
            self::cases(),
        );
    }

    public static function fromTenant(ManagedEnvironment $tenant): self
    {
        if ($tenant->trashed()) {
            return self::Archived;
        }

        return self::fromValue($tenant->lifecycle_status);
    }

    public static function fromValue(mixed $value, self $default = self::Active): self
    {
        return self::tryFromValue($value) ?? $default;
    }

    public static function tryFromValue(mixed $value): ?self
    {
        $normalized = self::normalize($value);

        return $normalized === null ? null : self::tryFrom($normalized);
    }

    public static function normalize(mixed $value): ?string
    {
        if ($value === null) {
            return null;
        }

        if ($value instanceof BackedEnum) {
            $value = $value->value;
        }

        if ($value instanceof Stringable) {
            $value = (string) $value;
        }

        if (! is_string($value)) {
            return null;
        }

        $normalized = strtolower(trim($value));
        $normalized = str_replace([' ', '-'], '_', $normalized);

        return $normalized !== '' ? $normalized : null;
    }

    public function label(): string
    {
        return match ($this) {
            self::Draft => 'Draft',
            self::Onboarding => 'Onboarding',
            self::Active => 'Active',
            self::Archived => 'Archived',
        };
    }

    public function isSelectableInStandardLane(): bool
    {
        return $this === self::Active;
    }

    public function isAdministrativelyDiscoverable(): bool
    {
        return true;
    }

    public function isViewableInLane(TenantInteractionLane $lane): bool
    {
        return match ($lane) {
            TenantInteractionLane::StandardActiveOperating => $this->isSelectableInStandardLane(),
            TenantInteractionLane::OnboardingWorkflow => in_array($this, [self::Draft, self::Onboarding], true),
            TenantInteractionLane::AdministrativeManagement, TenantInteractionLane::CanonicalWorkspaceRecord => true,
        };
    }

    public function supportsQuestion(TenantOperabilityQuestion $question, TenantInteractionLane $lane): bool
    {
        return match ($question) {
            TenantOperabilityQuestion::SelectorEligibility,
            TenantOperabilityQuestion::RememberedContextValidity => $lane === TenantInteractionLane::StandardActiveOperating && $this->isSelectableInStandardLane(),
            TenantOperabilityQuestion::EnvironmentBoundViewability => $lane === TenantInteractionLane::AdministrativeManagement,
            TenantOperabilityQuestion::CanonicalLinkedRecordViewability => $lane === TenantInteractionLane::CanonicalWorkspaceRecord,
            TenantOperabilityQuestion::ArchiveEligibility => $lane === TenantInteractionLane::AdministrativeManagement && $this->canArchive(),
            TenantOperabilityQuestion::RestoreEligibility => $lane === TenantInteractionLane::AdministrativeManagement && $this->canRestore(),
            TenantOperabilityQuestion::ResumeOnboardingEligibility => in_array($lane, [TenantInteractionLane::AdministrativeManagement, TenantInteractionLane::OnboardingWorkflow], true) && $this->canResumeOnboarding(),
            TenantOperabilityQuestion::OnboardingCompletionEligibility => $lane === TenantInteractionLane::OnboardingWorkflow && in_array($this, [self::Draft, self::Onboarding], true),
            TenantOperabilityQuestion::VerificationReadinessEligibility => match ($lane) {
                TenantInteractionLane::StandardActiveOperating => false,
                TenantInteractionLane::OnboardingWorkflow => in_array($this, [self::Draft, self::Onboarding], true),
                TenantInteractionLane::AdministrativeManagement => $this === self::Active,
                TenantInteractionLane::CanonicalWorkspaceRecord => false,
            },
            TenantOperabilityQuestion::AdministrativeDiscoverability => $this->isAdministrativelyDiscoverable(),
        };
    }

    public function canSelectAsContext(): bool
    {
        return $this->isSelectableInStandardLane();
    }

    public function canViewTenantSurface(): bool
    {
        return $this->isAdministrativelyDiscoverable();
    }

    public function canOperate(): bool
    {
        return $this === self::Active;
    }

    public function canArchive(): bool
    {
        return $this === self::Active;
    }

    public function canRestore(): bool
    {
        return $this === self::Archived;
    }

    public function canResumeOnboarding(): bool
    {
        return in_array($this, [self::Draft, self::Onboarding], true);
    }

    public function canReferenceInWorkspaceMonitoring(): bool
    {
        return true;
    }

    public function allowsManagementAction(string $actionKey): bool
    {
        return match ($actionKey) {
            'resume_onboarding' => $this->canResumeOnboarding(),
            'archive' => $this->canArchive(),
            'restore' => $this->canRestore(),
            default => false,
        };
    }
}
