<?php

declare(strict_types=1);

final class MyronOperatorStateUpdateBoundary
{
    /**
     * @var list<string>
     */
    private const FORBIDDEN_PREFIXES = [
        '.amphion/',
        '.git/',
        'dev-' . 'references/',
        'dev-' . 'prep/',
        'ops/',
        'app/tests/',
        'app/jsonm/tests/',
        'app/jsonm/definitions/',
        'app/system/uploads/',
        'app/uploads/',
        'app/storage/',
        'app/assets/media/',
    ];

    /**
     * @var list<string>
     */
    private const FORBIDDEN_EXACT_PATHS = [
        'app/jsonm/current-definition.json',
        'app/assets/runtime/css/runtime-token-overrides.css',
        'app/assets/runtime/css/runtime-fonts.css',
        'app/jsonm/definitions/index.json',
        'app/system/definitions/PageTemplateSeedContentLoader.php',
        'app/system/definitions/PassOneGuidanceIngestionService.php',
    ];

    /**
     * @var list<string>
     */
    private const PROTECTED_SNAPSHOT_PATHS = [
        'app/jsonm/current-definition.json',
        'app/assets/runtime/css/runtime-token-overrides.css',
        'app/assets/runtime/css/runtime-fonts.css',
        'app/jsonm/definitions',
        'app/uploads',
        'app/system/uploads',
        'app/storage',
        'app/assets/media',
    ];

    /**
     * @var list<string>
     */
    private const REQUIRED_ATTRIBUTION_SOURCE_PATHS = [
        'app/modules/content/public/PublishedPageHtmlAssembler.php',
        'app/system/license/CoreAttributionPolicy.php',
    ];

    /**
     * @var array<string, string>
     */
    private const TIERED_PATH_CAPABILITIES = [
        'app/modules/devops/' => 'updates.pro',
        'app/admin/routes/administration/funnels.php' => 'updates.pro',
        'app/admin/routes/funnels/' => 'updates.pro',
        'app/admin/routes/content/funnels.php' => 'updates.pro',
        'app/modules/funnels/' => 'updates.pro',
        'app/modules/quizzes/' => 'updates.pro',
        'app/api/actions/funnels/' => 'updates.pro',
        'app/admin/routes/content/lms-' => 'updates.pro',
        'app/modules/lms/' => 'updates.pro',
        'app/api/actions/lms/' => 'updates.pro',
        'app/admin/routes/design/section-variants.php' => 'updates.pro',
        'app/api/actions/design/UpdateSectionVariantAction.php' => 'updates.pro',
        'app/api/actions/design/CreateSectionVariantAction.php' => 'updates.pro',
    ];

    public static function isForbiddenUpdatePath(string $path): bool
    {
        $path = self::normalizePath($path);
        if ($path === '') {
            return true;
        }

        $basename = basename($path);
        if ($basename === '.env' || (str_starts_with($basename, '.env.') && $basename !== '.env.example')) {
            return true;
        }

        if ($path === 'app/assets/media/.gitignore') {
            return false;
        }

        if (in_array($path, self::FORBIDDEN_EXACT_PATHS, true)) {
            return true;
        }

        foreach (self::FORBIDDEN_PREFIXES as $prefix) {
            if ($path === rtrim($prefix, '/') || str_starts_with($path, $prefix)) {
                return true;
            }
        }

        return false;
    }

    public static function isSafeInstallRoot(string $path): bool
    {
        $path = self::normalizePath(rtrim($path, '/')) . '/';
        if (self::isForbiddenUpdatePath(rtrim($path, '/'))) {
            return false;
        }

        return preg_match('#^app/modules/[a-z][a-z0-9_]*(?:/[a-z][a-z0-9_]*)*/$#', $path) === 1
            || preg_match('#^app/extensions/[a-z][a-z0-9_]*/$#', $path) === 1;
    }

    /**
     * @return list<string>
     */
    public static function protectedSnapshotPaths(): array
    {
        return self::PROTECTED_SNAPSHOT_PATHS;
    }

    /**
     * @return list<string>
     */
    public static function requiredAttributionSourcePaths(): array
    {
        return self::REQUIRED_ATTRIBUTION_SOURCE_PATHS;
    }

    public static function requiredCapabilityForPath(string $path): string
    {
        $path = self::normalizePath($path);
        foreach (self::TIERED_PATH_CAPABILITIES as $prefix => $capability) {
            if ($path === rtrim($prefix, '/') || $path === $prefix || str_starts_with($path, $prefix)) {
                return $capability;
            }
        }

        return '';
    }

    public static function packageCoversCapability(string $declaredCapability, string $requiredCapability): bool
    {
        return self::updateCapabilityRank($declaredCapability) >= self::updateCapabilityRank($requiredCapability);
    }

    public static function updateCapabilityRank(string $capability): int
    {
        return match (trim($capability)) {
            'updates.security', 'updates.maintenance' => 10,
            'updates.feature' => 20,
            'updates.pro' => 30,
            'updates.agency' => 40,
            default => 0,
        };
    }

    public static function packageTierForCapability(string $capability): string
    {
        return match (trim($capability)) {
            'updates.agency' => 'agency',
            'updates.pro' => 'pro',
            default => 'core',
        };
    }

    public static function normalizePath(string $path): string
    {
        $normalized = str_replace('\\', '/', trim($path));
        while (str_starts_with($normalized, './')) {
            $normalized = substr($normalized, 2);
        }

        return $normalized;
    }
}
