<?php

/**
 * Tier Matrix Manager
 *
 * Reads and provides access to the tier matrix configuration
 * Single source of truth for feature tiering
 *
 * @package ProRank\SEO\Core
 * @since   0.1.0
 */

declare(strict_types=1);

namespace ProRank\SEO\Core;

use Symfony\Component\Yaml\Yaml;
use Symfony\Component\Yaml\Exception\ParseException;

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


/**
 * Tier Matrix class
 */


class TierMatrix {

    /**
     * Tier matrix data
     *
     * @var array<string, mixed>
     */
    private array $matrix = [];

    /**
     * Path to tier matrix file
     *
     * @var string
     */
    private string $matrix_file;

    /**
     * Tier hierarchy for comparison
     *
     * @var array<string, int>
     */
    private array $tier_levels = [
        'free'     => 0,
        'pro'      => 2,
        'business' => 3,
        'agency'   => 4,
    ];

    /**
     * Tier aliases (legacy → canonical)
     *
     * @var array<string, string>
     */
    private array $tier_aliases = [
        'core' => 'pro',
    ];

    /**
     * Commercial tiers (4-tier model for display)
     *
     * @var array<string>
     */
    private array $commercial_tiers = ['free', 'pro', 'business', 'agency'];

    /**
     * Constructor
     */
    public function __construct() {
        $this->matrix_file = PRORANK_PLUGIN_DIR . 'config/tier-matrix.yml';
        $this->load_matrix();
    }

    /**
     * Load tier matrix from YAML file
     *
     * @return void
     */
    private function load_matrix(): void {
        if ( ! file_exists( $this->matrix_file ) ) {
            return;
        }

        try {
            $content = file_get_contents( $this->matrix_file );
            if ( false === $content ) {
                return;
            }

            $this->matrix = Yaml::parse( $content );
        } catch ( ParseException $e ) {
            // Log error but don't break the plugin
            prorank_log( 'ProRank SEO: Failed to parse tier matrix - ' . $e->getMessage() );
        }
    }

    /**
     * Normalize tier to canonical name
     *
     * Converts legacy tier names (e.g., 'core') to canonical names (e.g., 'pro')
     *
     * @param string $tier Tier name (may be legacy alias).
     * @return string Canonical tier name.
     */
    public function normalize_tier( string $tier ): string {
        return $this->tier_aliases[ $tier ] ?? $tier;
    }

    /**
     * Get required tier for a module
     *
     * @param string $module_slug Module slug.
     * @return string Required tier (defaults to 'free' if not found).
     */
    public function get_module_tier( string $module_slug ): string {
        $tier = $this->matrix['modules'][ $module_slug ] ?? 'free';
        return $this->normalize_tier( $tier );
    }

    /**
     * Get required tier for a specific feature
     *
     * @param string $module_slug  Module slug.
     * @param string $feature_slug Feature slug within the module.
     * @return string Required tier (defaults to module tier or 'free').
     */
    public function get_feature_tier( string $module_slug, string $feature_slug ): string {
        // Check if feature has specific tier requirement
        if ( isset( $this->matrix['features'][ $module_slug ][ $feature_slug ] ) ) {
            $tier = $this->matrix['features'][ $module_slug ][ $feature_slug ];
            return $this->normalize_tier( $tier );
        }

        // Fall back to module tier
        return $this->get_module_tier( $module_slug );
    }

    /**
     * Check if a tier meets the requirement
     *
     * @param string $current_tier  Current user/license tier.
     * @param string $required_tier Required tier for feature.
     * @return bool True if current tier meets or exceeds requirement.
     */
    public function tier_meets_requirement( string $current_tier, string $required_tier ): bool {
        // Normalize both tiers to handle legacy aliases
        $current_tier  = $this->normalize_tier( $current_tier );
        $required_tier = $this->normalize_tier( $required_tier );

        $current_level  = $this->tier_levels[ $current_tier ] ?? -1;
        $required_level = $this->tier_levels[ $required_tier ] ?? 999;

        return $current_level >= $required_level;
    }

    /**
     * Get all modules for a specific tier (excluding higher tiers)
     *
     * @param string $tier Tier name.
     * @return array<string> Module slugs available at this tier.
     */
    public function get_modules_for_tier( string $tier ): array {
        $modules    = [];
        $tier       = $this->normalize_tier( $tier );
        $tier_level = $this->tier_levels[ $tier ] ?? -1;

        foreach ( $this->matrix['modules'] ?? [] as $module_slug => $module_tier ) {
            $module_tier  = $this->normalize_tier( $module_tier );
            $module_level = $this->tier_levels[ $module_tier ] ?? 999;
            if ( $module_level <= $tier_level ) {
                $modules[] = $module_slug;
            }
        }

        return $modules;
    }

    /**
     * Get all features for a module at a specific tier
     *
     * @param string $module_slug Module slug.
     * @param string $tier        Tier name.
     * @return array<string> Feature slugs available at this tier.
     */
    public function get_features_for_module_tier( string $module_slug, string $tier ): array {
        $features   = [];
        $tier       = $this->normalize_tier( $tier );
        $tier_level = $this->tier_levels[ $tier ] ?? -1;

        foreach ( $this->matrix['features'][ $module_slug ] ?? [] as $feature_slug => $feature_tier ) {
            $feature_tier  = $this->normalize_tier( $feature_tier );
            $feature_level = $this->tier_levels[ $feature_tier ] ?? 999;
            if ( $feature_level <= $tier_level ) {
                $features[] = $feature_slug;
            }
        }

        return $features;
    }

    /**
     * Get tier display name
     *
     * @param string $tier Tier slug.
     * @return string Display name.
     */
    public function get_tier_name( string $tier ): string {
        // Normalize to canonical tier for display
        $tier = $this->normalize_tier( $tier );
        return $this->matrix['tier_names'][ $tier ] ?? ucfirst( $tier );
    }

    /**
     * Get tier description
     *
     * @param string $tier Tier slug.
     * @return string Description.
     */
    public function get_tier_description( string $tier ): string {
        $tier = $this->normalize_tier( $tier );
        return $this->matrix['tier_descriptions'][ $tier ] ?? '';
    }

    /**
     * Get commercial tiers for display (4-tier model)
     *
     * @return array<string> List of commercial tier slugs.
     */
    public function get_commercial_tiers(): array {
        return $this->commercial_tiers;
    }

    /**
     * Check if a tier is a legacy alias
     *
     * @param string $tier Tier name.
     * @return bool True if tier is a legacy alias.
     */
    public function is_legacy_tier( string $tier ): bool {
        return isset( $this->tier_aliases[ $tier ] );
    }

    /**
     * Get all tier data for frontend use
     *
     * @return array<string, mixed> Tier matrix data.
     */
    public function get_matrix_data(): array {
        return [
            'modules'           => $this->matrix['modules'] ?? [],
            'features'          => $this->matrix['features'] ?? [],
            'tier_hierarchy'    => $this->matrix['tier_hierarchy'] ?? [],
            'tier_names'        => $this->matrix['tier_names'] ?? [],
            'tier_descriptions' => $this->matrix['tier_descriptions'] ?? [],
            'commercial_tiers'  => $this->commercial_tiers,
        ];
    }

    /**
     * Check if matrix is loaded
     *
     * @return bool True if matrix data is available.
     */
    public function is_loaded(): bool {
        return ! empty( $this->matrix );
    }
}
