<?php

declare(strict_types=1);

require_once __DIR__ . '/CapabilityCatalog.php';

final class MyronEntitlementGate
{
    public function __construct(private readonly MyronLicenseRepository $repository)
    {
    }

    /**
     * @return array{outcome:string, reason:string, capability:string, plan:string, status:string}
     */
    public function evaluate(string $capability): array
    {
        $snapshot = $this->repository->currentSnapshot();
        $capability = trim($capability);
        if ($capability === '') {
            return $this->decision('blocked', 'missing_capability', '', $snapshot);
        }

        if (!MyronLicenseStatus::allowsRuntime($snapshot->status)) {
            return $this->decision('blocked', 'license_status_' . $snapshot->status, $capability, $snapshot);
        }
        if (!array_key_exists($capability, $snapshot->capabilities)) {
            return $this->decision('warn', 'unknown_capability', $capability, $snapshot);
        }
        if ($snapshot->capabilities[$capability] !== true) {
            return $this->decision('blocked', 'capability_not_entitled', $capability, $snapshot);
        }
        if (in_array($snapshot->status, [MyronLicenseStatus::GRACE, MyronLicenseStatus::PAYMENT_FAILED, MyronLicenseStatus::STALE], true)) {
            return $this->decision('warn', 'license_status_' . $snapshot->status, $capability, $snapshot);
        }

        return $this->decision('allowed', 'entitled', $capability, $snapshot);
    }

    public function allows(string $capability): bool
    {
        $decision = $this->evaluate($capability);
        return in_array($decision['outcome'], ['allowed', 'warn'], true);
    }

    /**
     * @return array<string, string>
     */
    public static function initialCapabilityMap(): array
    {
        return MyronCapabilityCatalog::descriptions();
    }

    /**
     * @param list<string>|null $presentModules
     * @return array<string, string>
     */
    public static function operatorCapabilityMap(?array $presentModules = null): array
    {
        return MyronCapabilityCatalog::operatorDescriptions($presentModules);
    }

    /**
     * @return array{outcome:string, reason:string, capability:string, plan:string, status:string}
     */
    private function decision(string $outcome, string $reason, string $capability, MyronEntitlementSnapshot $snapshot): array
    {
        return [
            'outcome' => $outcome,
            'reason' => $reason,
            'capability' => $capability,
            'plan' => $snapshot->plan,
            'status' => $snapshot->status,
        ];
    }

}
