<?php

namespace Formatrica\Capability;

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

use Formatrica\License\License_Manager_Interface;

/**
 * The single service that answers capability questions.
 *
 * Seeds every known capability to false, then merges registered provider
 * maps (a capability is available if ANY provider grants it). Renderers,
 * validators, save rules, REST controllers, and the builder boot payload
 * should ask Feature_Gate — never License_Service directly. Unknown keys
 * always return false.
 */
final class Feature_Gate
{
    /**
     * @var list<Capability_Provider_Interface>
     */
    private array $providers = [];

    /**
     * @var array<string, bool>|null Resolved map; null until first resolve.
     */
    private ?array $resolved = null;

    /**
     * The boot-resolved gate, shared with services (like Premium_Save_Guard)
     * that are constructed outside the service locator. Set during plugin boot.
     */
    private static ?Feature_Gate $default = null;

    public function __construct(private License_Manager_Interface $license)
    {
    }

    /**
     * Register the boot-resolved gate as the process default.
     */
    public static function set_default(Feature_Gate $gate): void
    {
        self::$default = $gate;
    }

    /**
     * The boot-resolved default gate, or null before boot has registered one.
     */
    public static function get_default(): ?Feature_Gate
    {
        return self::$default;
    }

    /**
     * Register a capability provider. Order does not matter (OR merge).
     */
    public function add_provider(Capability_Provider_Interface $provider): void
    {
        $this->providers[] = $provider;
        $this->resolved = null;
    }

    /**
     * Swap the license manager (e.g. when the Pro package registers a real one).
     */
    public function set_license_manager(License_Manager_Interface $license): void
    {
        $this->license = $license;
    }

    /**
     * Whether a capability is available.
     */
    public function has(string $key): bool
    {
        return $this->all()[$key] ?? false;
    }

    /**
     * The fully resolved capability map (every known key present).
     *
     * @return array<string, bool>
     */
    public function all(): array
    {
        if ($this->resolved !== null) {
            return $this->resolved;
        }

        $map = [];
        foreach (Capabilities::all() as $key) {
            $map[$key] = false;
        }

        foreach ($this->providers as $provider) {
            foreach ($provider->get_capabilities() as $key => $available) {
                if (array_key_exists($key, $map)) {
                    $map[$key] = $map[$key] || (bool) $available;
                }
            }
        }

        $this->resolved = $map;

        return $map;
    }

    /**
     * Redacted license summary for the builder/admin UI. Never contains the
     * raw license key or auth token.
     *
     * @return array<string, mixed>
     */
    public function license_summary(): array
    {
        return $this->license->get_state()->to_summary();
    }
}
