<?php

declare(strict_types=1);

require_once __DIR__ . '/EntitlementSnapshot.php';
require_once __DIR__ . '/LicenseStatus.php';

final class MyronLicenseRemediationState
{
    public const MODE_NORMAL = 'normal';
    public const MODE_GRACE = 'grace';
    public const MODE_RENEWAL_REQUIRED = 'renewal_required';
    public const MODE_COMPLIANCE_LIMITED = 'compliance_limited';
    public const MODE_VERIFICATION_EXCEPTION = 'verification_exception';

    private const SEVERITY_MONITOR = 'monitor';
    private const SEVERITY_REVIEW = 'review';
    private const SEVERITY_ENFORCEMENT_REVIEW = 'enforcement_review';

    public function __construct(
        private readonly string $mode,
        private readonly string $customerLabel,
        private readonly string $customerMessage,
        private readonly string $internalSeverity,
        private readonly bool $publicContentReadable,
        private readonly bool $packageActionsAllowed,
        private readonly bool $featureMutationAllowed,
    ) {
    }

    public static function fromSnapshot(MyronEntitlementSnapshot $snapshot, string $lastValidationStatus = '', string $lastValidationReason = ''): self
    {
        $status = MyronLicenseStatus::normalize($snapshot->status);
        $lastValidationStatus = strtolower(trim($lastValidationStatus));
        $lastValidationReason = strtolower(trim($lastValidationReason));

        if ($lastValidationStatus === 'failed' && in_array($status, [MyronLicenseStatus::ACTIVE, MyronLicenseStatus::GRACE, MyronLicenseStatus::STALE], true)) {
            return new self(
                self::MODE_VERIFICATION_EXCEPTION,
                'Verification needs attention',
                'The last license verification did not complete. Public content stays available where safe while administrators refresh the license.',
                self::severityForReason($lastValidationReason),
                true,
                false,
                $status !== MyronLicenseStatus::STALE
            );
        }

        return match ($status) {
            MyronLicenseStatus::ACTIVE => new self(
                self::MODE_NORMAL,
                'Active',
                'This site has an active entitlement snapshot.',
                self::SEVERITY_MONITOR,
                true,
                true,
                true
            ),
            MyronLicenseStatus::GRACE => new self(
                self::MODE_GRACE,
                'Grace period',
                'This site is in a grace period. Public content stays available while renewal is resolved.',
                self::SEVERITY_MONITOR,
                true,
                true,
                true
            ),
            MyronLicenseStatus::PAYMENT_FAILED => new self(
                self::MODE_RENEWAL_REQUIRED,
                'Billing attention required',
                'Public content stays available where safe. New licensed feature changes may be limited until renewal is resolved.',
                self::SEVERITY_REVIEW,
                true,
                false,
                false
            ),
            MyronLicenseStatus::STALE => new self(
                self::MODE_VERIFICATION_EXCEPTION,
                'Verification stale',
                'The entitlement snapshot is stale. Public content stays available where safe while administrators refresh the license.',
                self::SEVERITY_REVIEW,
                true,
                false,
                false
            ),
            MyronLicenseStatus::EXPIRED => new self(
                self::MODE_RENEWAL_REQUIRED,
                'Renewal required',
                'This license is expired. Public content is not hard-shut by default, but licensed package installation and new feature mutations are limited.',
                self::SEVERITY_REVIEW,
                true,
                false,
                false
            ),
            MyronLicenseStatus::DISABLED,
            MyronLicenseStatus::CANCELED,
            MyronLicenseStatus::INVALID => new self(
                self::MODE_COMPLIANCE_LIMITED,
                'Compliance limited',
                'This site needs license attention before licensed feature changes or package installation continue.',
                self::SEVERITY_ENFORCEMENT_REVIEW,
                true,
                false,
                false
            ),
            default => new self(
                self::MODE_COMPLIANCE_LIMITED,
                'License required',
                'Activate a license to use licensed administration and package features.',
                self::SEVERITY_REVIEW,
                true,
                false,
                false
            ),
        };
    }

    public static function severityForReason(string $reasonCode): string
    {
        $reasonCode = strtolower(trim($reasonCode));
        if (str_contains($reasonCode, 'not_found') || str_contains($reasonCode, 'invalid') || str_contains($reasonCode, 'disabled')) {
            return self::SEVERITY_ENFORCEMENT_REVIEW;
        }
        if (str_contains($reasonCode, 'expired') || str_contains($reasonCode, 'payment') || str_contains($reasonCode, 'mismatch')) {
            return self::SEVERITY_REVIEW;
        }

        return self::SEVERITY_MONITOR;
    }

    /**
     * @return array<string, mixed>
     */
    public function toCustomerArray(): array
    {
        return [
            'mode' => $this->mode,
            'label' => $this->customerLabel,
            'message' => $this->customerMessage,
            'publicContentReadable' => $this->publicContentReadable,
            'packageActionsAllowed' => $this->packageActionsAllowed,
            'featureMutationAllowed' => $this->featureMutationAllowed,
        ];
    }

    /**
     * @return array<string, mixed>
     */
    public function toInternalAuditDetail(): array
    {
        return $this->toCustomerArray() + [
            'internalSeverity' => $this->internalSeverity,
            'humanReviewRequired' => $this->internalSeverity !== self::SEVERITY_MONITOR,
        ];
    }

    public function mode(): string
    {
        return $this->mode;
    }

    public function customerLabel(): string
    {
        return $this->customerLabel;
    }

    public function customerMessage(): string
    {
        return $this->customerMessage;
    }

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