<?php

declare(strict_types=1);

final class MyronCapabilityCatalog
{
    private const NEVER = 'never';
    private const INSTALL_GRANT = 'install-grant';

    /**
     * @return array<string, array{description:string, minimumTier:string, package:string, visibility:string, modules:list<string>}>
     */
    public static function definitions(): array
    {
        return [
            'cms_runtime' => self::core('Baseline CMS runtime available to every licensed install.', 'core-foundation'),
            'content_authoring' => self::core('Baseline page and content authoring.', 'core-content'),
            'design_systems' => self::core('Governed design tokens, JSONM, templates, and styling controls.', 'core-design'),
            'database_runtime' => self::core('Database-backed installed runtime boundary.', 'core-foundation'),
            'production_use' => self::core('One real production site for Core and tier-scaled site counts above it.', 'core-foundation'),
            'mcp.site_operations' => self::core('MCP access for entitled CMS operations.', 'core-mcp'),
            'mcp.byok_ai_actions' => self::pro('MCP actions backed by configured BYOK LLM providers.', 'pro-byok-ai', 'hidden'),
            'ai.byok_provider_config' => self::pro('BYOK LLM provider configuration.', 'pro-byok-ai', 'hidden'),
            'operators.unlimited' => self::personal('Unlimited operators and multi-user/multi-role assignment.', 'identity'),
            'attribution.public_bar' => self::core('Core public Built with MyronCMS attribution bar.', 'core-foundation'),
            'attribution.remove_public_bar' => self::personal('Remove public attribution bar.', 'branding'),
            'branding.white_label' => self::enterprise('Full white-label/CMSaaS product identity control.', 'enterprise-whitelabel'),
            'audit.write_substrate' => self::core('Internal security/auth/license/update event logging substrate.', 'core-foundation'),
            'audit.admin_surface' => self::personal('Operator-facing audit/activity log UI.', 'audit'),
            'audit.export' => self::pro('Audit search, filter, export, and compliance-style reporting.', 'audit'),
            'search.public' => self::core('Native public/admin search and rebuild substrate.', 'core-search'),
            'analytics.native' => self::core('Native MyronCMS analytics capture and baseline reporting.', 'core-analytics-native'),
            'analytics.providers' => self::pro('External analytics providers and tag integrations.', 'pro-provider-integrations'),
            'code.custom_injection' => self::pro('Generic custom head/body/footer code injection.', 'pro-provider-integrations'),
            'forms.general' => self::core('General forms, contact forms, notifications, and storage.', 'core-forms-mail'),
            'forms.csv_export' => self::core('CSV download/export for form submissions.', 'core-forms-mail'),
            'forms.webhooks' => self::pro('Webhook delivery and automation sync for submissions.', 'pro-webhooks'),
            'mail.multiple_configs' => self::core('Multiple mail/SMTP configurations and per-form assignment.', 'core-forms-mail'),
            'verification.myron_engine' => self::core('First-party Myron Verification Engine and threat detection.', 'core-forms-mail'),
            'payment.providers' => self::personal('Site-governed payment provider configuration.', 'personal-payment', 'visible', ['commerce']),
            'commerce.checkout_primitives' => self::personal('Payment buttons and simple one-off checkout primitives.', 'personal-payment', 'visible', ['commerce']),
            'commerce.full' => self::pro('Full catalog, cart, checkout, and order management.', 'pro-commerce', 'visible', ['commerce']),
            'site_type.biz' => self::core('Business site type.', 'core-site-types'),
            'site_type.blog' => self::core('Blog/publication site type.', 'core-site-types'),
            'site_type.port' => self::personal('Portfolio site type.', 'personal-site-types'),
            'site_type.news' => self::personal('News publication site type.', 'personal-site-types'),
            'site_type.saas' => self::personal('Software product site type.', 'personal-site-types'),
            'site_type.crs' => self::personal('Creative studio site type.', 'personal-site-types'),
            'site_type.agy' => self::pro('Agency site type.', 'pro-site-types'),
            'site_type.ecom' => self::pro('E-commerce site type.', 'pro-site-types'),
            'site_type.edu' => self::pro('Education/courses site type.', 'pro-site-types', 'visible', ['lms']),
            'site_type.mkt' => self::pro('Marketing/funnel site type.', 'pro-site-types', 'visible', ['funnels', 'quizzes', 'content/vcards', 'content/personal_pages']),
            'site_type.rst' => self::pro('Restaurant/hospitality site type.', 'pro-site-types'),
            'site_type.ps' => self::pro('Professional services site type.', 'pro-site-types'),
            'site_type.bkg' => self::pro('Booking/marketplace site type.', 'pro-site-types'),
            'site_types.catalog' => self::installGrant('Full non-core site-type catalog, granted on activation of any paid Module.', 'site-types-catalog', 'visible'),
            'editorial.workflow' => self::pro('Formal editorial workflow states and approval queues.', 'pro-editorial'),
            'editorial.diff_views' => self::pro('Comparative editorial diff views.', 'pro-editorial'),
            'editorial.scheduled_publish' => self::pro('Scheduled publishing.', 'pro-editorial'),
            'templates.document' => self::pro('Document templates governed in the Design context.', 'pro-editorial'),
            'templates.custom_site' => self::core('Custom site templates.', 'core-design'),
            'templates.custom_section' => self::core('Custom section templates.', 'core-design'),
            'templates.section_variants' => self::pro('Saved custom section variants.', 'pro-extension-authoring'),
            'components.custom_assembled' => self::pro('Custom assembled components/primitives.', 'pro-extension-authoring'),
            'seo.core' => self::core('Core SEO, social metadata, feeds, sitemap, robots, and AI-native discovery.', 'core-seo'),
            'seo.jsonld_override' => self::personal('Custom per-page JSON-LD override.', 'seo'),
            'feeds.public' => self::core('Public RSS, Atom, and JSON feeds.', 'core-seo'),
            'feeds.custom_api' => self::pro('Private/custom/API feed endpoints and automation.', 'pro-provider-integrations'),
            'redirects.manual' => self::core('Manual redirect management and validation.', 'core-seo'),
            'redirects.bulk_api' => self::pro('Bulk redirect import/export and API automation.', 'pro-provider-integrations'),
            'snapshots.basic' => self::core('Basic site export/import, restore, and dry-run/impact preview.', 'core-content'),
            'snapshots.devops' => self::pro('DevOps snapshots and environment promotion.', 'pro-devops', 'visible', ['devops']),
            'devops.environments' => self::pro('Environment pairs, deployment keys, and promotion workflows.', 'pro-devops', 'visible', ['devops']),
            'webhooks.outbound' => self::pro('Outbound webhooks, delivery logs, and retries.', 'pro-webhooks'),
            'api.inbound_writes' => self::pro('Inbound API writes from external systems.', 'pro-webhooks'),
            'extensions.install' => self::core('Install signed Marketplace extension packages.', 'core-marketplace-client', 'hidden'),
            'extensions.marketplace_install' => self::core('Marketplace browse/install/update/uninstall.', 'core-marketplace-client'),
            'extensions.local_registration' => self::pro('Local/manual extension registration.', 'pro-extension-authoring'),
            'extensions.authoring' => self::pro('In-install extension authoring tools.', 'pro-extension-authoring'),
            'modules.install' => self::installGrant('Install signed first-party paid Module packages.', 'module-installer'),
            'updates.security' => self::core('Security updates available to all valid licensed installs.', 'updates'),
            'updates.maintenance' => self::core('Critical compatibility and maintenance updates.', 'updates'),
            'updates.feature' => self::core('Tier-filtered feature updates.', 'updates'),
            'updates.pro' => self::pro('Pro feature update packages.', 'updates'),
            'updates.agency' => self::agency('Agency feature update packages.', 'updates'),
            'agency_client_sites' => self::agency('Agency operational boundary for multiple client sites.', 'agency'),
            'source.core_editing_supported' => self::never('Raw MyronCMS core PHP/source editing is not supported in any tier.', 'legal'),
        ];
    }

    /**
     * @return array<string, bool>
     */
    public static function defaultCapabilities(string $tier): array
    {
        $capabilities = [];
        foreach (self::definitions() as $key => $definition) {
            $capabilities[$key] = self::allows($tier, $key);
        }
        $capabilities['multi_environment_workflow'] = $capabilities['devops.environments'];
        $capabilities['deployment_group'] = $capabilities['devops.environments'];

        return $capabilities;
    }

    public static function allows(string $tier, string $capability): bool
    {
        $definitions = self::definitions();
        if (!isset($definitions[$capability])) {
            return false;
        }

        $minimumTier = $definitions[$capability]['minimumTier'];
        if ($minimumTier === self::NEVER) {
            return false;
        }
        if ($minimumTier === self::INSTALL_GRANT) {
            return false;
        }
        if ($capability === 'attribution.public_bar') {
            return MyronLicenseTier::normalize($tier) === MyronLicenseTier::CORE;
        }
        if (MyronLicenseTier::isEnterprise($tier)) {
            return true;
        }

        return MyronLicenseTier::isAtLeast($tier, $minimumTier);
    }

    /**
     * @return array<string, string>
     */
    public static function descriptions(): array
    {
        $descriptions = [];
        foreach (self::definitions() as $key => $definition) {
            $descriptions[$key] = $definition['description'];
        }

        return $descriptions;
    }

    /**
     * @param list<string>|null $presentModules
     * @return array<string, string>
     */
    public static function operatorDescriptions(?array $presentModules = null): array
    {
        if ($presentModules === null && function_exists('myronModuleRegistry')) {
            $presentModules = myronModuleRegistry()->presentModules();
        }
        $present = array_fill_keys(array_map('strval', $presentModules ?? []), true);
        $descriptions = [];

        foreach (self::definitions() as $key => $definition) {
            if (($definition['visibility'] ?? 'visible') === 'hidden') {
                continue;
            }
            if ($definition['minimumTier'] === MyronLicenseTier::CORE) {
                $descriptions[$key] = $definition['description'];
                continue;
            }
            foreach ($definition['modules'] as $module) {
                if (isset($present[$module])) {
                    $descriptions[$key] = $definition['description'];
                    break;
                }
            }
        }

        return $descriptions;
    }

    public static function isInvariantDisabled(string $capability): bool
    {
        $definitions = self::definitions();
        return ($definitions[$capability]['minimumTier'] ?? null) === self::NEVER;
    }

    /**
     * @return list<string>
     */
    public static function packagesFor(string $tier): array
    {
        $packages = [];
        foreach (self::definitions() as $key => $definition) {
            if (self::allows($tier, $key) && $definition['package'] !== '') {
                $packages[$definition['package']] = true;
            }
        }

        return array_keys($packages);
    }

    /**
     * @return array{description:string, minimumTier:string, package:string, visibility:string, modules:list<string>}
     */
    private static function core(string $description, string $package, string $visibility = 'visible', array $modules = []): array
    {
        return self::definition($description, MyronLicenseTier::CORE, $package, $visibility, $modules);
    }

    /**
     * @return array{description:string, minimumTier:string, package:string, visibility:string, modules:list<string>}
     */
    private static function personal(string $description, string $package, string $visibility = 'visible', array $modules = []): array
    {
        return self::definition($description, MyronLicenseTier::PERSONAL, $package, $visibility, $modules);
    }

    /**
     * @return array{description:string, minimumTier:string, package:string, visibility:string, modules:list<string>}
     */
    private static function pro(string $description, string $package, string $visibility = 'visible', array $modules = []): array
    {
        return self::definition($description, MyronLicenseTier::PRO, $package, $visibility, $modules);
    }

    /**
     * @return array{description:string, minimumTier:string, package:string, visibility:string, modules:list<string>}
     */
    private static function agency(string $description, string $package, array $modules = []): array
    {
        return self::definition($description, MyronLicenseTier::AGENCY, $package, 'visible', $modules);
    }

    /**
     * @return array{description:string, minimumTier:string, package:string, visibility:string, modules:list<string>}
     */
    private static function enterprise(string $description, string $package, array $modules = []): array
    {
        return self::definition($description, MyronLicenseTier::ENTERPRISE, $package, 'visible', $modules);
    }

    /**
     * @return array{description:string, minimumTier:string, package:string, visibility:string, modules:list<string>}
     */
    private static function never(string $description, string $package): array
    {
        return self::definition($description, self::NEVER, $package, 'hidden');
    }

    /**
     * @return array{description:string, minimumTier:string, package:string, visibility:string, modules:list<string>}
     */
    private static function installGrant(string $description, string $package, string $visibility = 'hidden'): array
    {
        return self::definition($description, self::INSTALL_GRANT, $package, $visibility);
    }

    /**
     * @param list<string> $modules
     * @return array{description:string, minimumTier:string, package:string, visibility:string, modules:list<string>}
     */
    private static function definition(string $description, string $minimumTier, string $package, string $visibility, array $modules = []): array
    {
        return [
            'description' => $description,
            'minimumTier' => $minimumTier,
            'package' => $package,
            'visibility' => $visibility,
            'modules' => array_values(array_unique(array_map('strval', $modules))),
        ];
    }
}
