<?php

namespace Formatrica\Capability;

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

use Formatrica\Capability\Rules\Advanced_Validations_Rule;
use Formatrica\Capability\Rules\Calculation_Field_Rule;
use Formatrica\Capability\Rules\Checkbox_Group_Field_Rule;
use Formatrica\Capability\Rules\Conditional_Logic_Rule;
use Formatrica\Capability\Rules\Custom_Field_Attrs_Rule;
use Formatrica\Capability\Rules\Divider_Field_Rule;
use Formatrica\Capability\Rules\Drafts_Rule;
use Formatrica\Capability\Rules\Dynamic_Select_Field_Rule;
use Formatrica\Capability\Rules\Email_Template_Rule;
use Formatrica\Capability\Rules\Geolocation_Field_Rule;
use Formatrica\Capability\Rules\Headless_Submission_Rule;
use Formatrica\Capability\Rules\Hubspot_Pro_Rule;
use Formatrica\Capability\Rules\Heading_Field_Rule;
use Formatrica\Capability\Rules\Multi_File_Field_Rule;
use Formatrica\Capability\Rules\Multi_Step_Rule;
use Formatrica\Capability\Rules\Payments_Hard_Gate_Rule;
use Formatrica\Capability\Rules\Price_Field_Rule;
use Formatrica\Capability\Rules\Rating_Field_Rule;
use Formatrica\Capability\Rules\Rich_Text_Field_Rule;
use Formatrica\Capability\Rules\Salesforce_Pro_Rule;
use Formatrica\Capability\Rules\Static_Image_Field_Rule;
use Formatrica\Capability\Rules\Submit_Redirect_Rule;
use Formatrica\Capability\Rules\Submitter_Email_Rule;
use Formatrica\Capability\Rules\Theme_Preset_Rule;
use Formatrica\Capability\Rules\Twilio_Pro_Rule;
use Formatrica\Capability\Rules\Webhook_Auth_Rule;
use Formatrica\Capability\Rules\Webhook_Unlimited_Rule;
use Formatrica\Capability\Rules\Wrapper_Class_Rule;
use Formatrica\License\Null_License_Manager;

/**
 * Fail-closed save-path enforcement for premium features.
 *
 * Owns a list of Premium_Config_Rule_Interface rules. For each rule whose
 * capability is unavailable on the resolved Feature_Gate, it calls the rule's
 * enforce() to revert unauthorized config and collect rejection entries. The
 * guard runs inside Form_Repository::save() so every save path is protected
 * independently of REST.
 */
final class Premium_Save_Guard
{
    /**
     * @var list<Premium_Config_Rule_Interface>
     */
    private array $rules = [];

    public function __construct(private Feature_Gate $gate)
    {
    }

    public function add_rule(Premium_Config_Rule_Interface $rule): void
    {
        $this->rules[] = $rule;
    }

    /**
     * Run every applicable rule against the config.
     *
     * @param array<string, mixed> $config   Sanitised form config, mutated by reference.
     * @param array<string, mixed> $existing  Previously-stored config.
     * @return list<array<string, string>>    Accumulated rejection entries.
     */
    public function enforce(array &$config, array $existing): array
    {
        $rejected = [];

        foreach ($this->rules as $rule) {
            // Authorized → the rule does not run; saved config passes through.
            if ($this->gate->has($rule->capability())) {
                continue;
            }

            foreach ($rule->enforce($config, $existing) as $entry) {
                $rejected[] = $entry;
            }
        }

        return $rejected;
    }

    /**
     * Build the default guard using the boot-resolved (Pro-aware) gate, with a
     * fail-closed Free gate fallback if boot has not registered one yet.
     */
    public static function default(): self
    {
        $gate = Feature_Gate::get_default();

        if (!$gate instanceof Feature_Gate) {
            $gate = new Feature_Gate(new Null_License_Manager());
            $gate->add_provider(new Free_Capability_Provider());
        }

        $guard = new self($gate);
        $guard->register_default_rules();

        return $guard;
    }

    /**
     * Register the foundation rule set. Real per-feature rules are added here as
     * they ship; the test rule proves the save-path mechanism end-to-end.
     */
    public function register_default_rules(): void
    {
        // Two/three-column layout is Free — no save-guard rule (see Free_Capability_Provider).
        $this->add_rule(new Multi_Step_Rule());
        $this->add_rule(new Conditional_Logic_Rule());
        $this->add_rule(new Submit_Redirect_Rule());
        $this->add_rule(new Wrapper_Class_Rule());
        $this->add_rule(new Custom_Field_Attrs_Rule());
        $this->add_rule(new Divider_Field_Rule());
        $this->add_rule(new Heading_Field_Rule());
        $this->add_rule(new Rating_Field_Rule());
        $this->add_rule(new Static_Image_Field_Rule());
        $this->add_rule(new Checkbox_Group_Field_Rule());
        $this->add_rule(new Geolocation_Field_Rule());
        $this->add_rule(new Multi_File_Field_Rule());
        $this->add_rule(new Rich_Text_Field_Rule());
        $this->add_rule(new Dynamic_Select_Field_Rule());
        $this->add_rule(new Calculation_Field_Rule());
        $this->add_rule(new Advanced_Validations_Rule());
        $this->add_rule(new Headless_Submission_Rule());
        $this->add_rule(new Drafts_Rule());
        $this->add_rule(new Submitter_Email_Rule());
        $this->add_rule(new Email_Template_Rule());
        $this->add_rule(new Payments_Hard_Gate_Rule());
        $this->add_rule(new Price_Field_Rule());
        $this->add_rule(new Theme_Preset_Rule());
        $this->add_rule(new Hubspot_Pro_Rule());
        $this->add_rule(new Salesforce_Pro_Rule());
        $this->add_rule(new Webhook_Unlimited_Rule());
        $this->add_rule(new Webhook_Auth_Rule());
        $this->add_rule(new Twilio_Pro_Rule());
    }
}
