<?php

/**
 * Migration Manager
 *
 * Handles plugin version upgrades and data migrations,
 * including tier changes and settings migrations.
 *
 * @package ProRank\SEO\Core
 * @since   0.1.0
 */

declare(strict_types=1);

namespace ProRank\SEO\Core;

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


/**
 * Migration class
 */


class Migration {

    /**
     * Settings manager instance
     *
     * @var SettingsManager
     */
    private SettingsManager $settings_manager;

    /**
     * License manager instance
     *
     * @var LicenseManager
     */
    private LicenseManager $license_manager;

    /**
     * Tier matrix instance
     *
     * @var TierMatrix|null
     */
    private ?TierMatrix $tier_matrix = null;

    /**
     * Option key for storing plugin version
     */
    private const VERSION_OPTION = 'prorank_seo_version';

    /**
     * Option key for storing migration history
     */
    private const MIGRATION_HISTORY_OPTION = 'prorank_seo_migration_history';

    /**
     * Constructor
     *
     * @param SettingsManager $settings_manager Settings manager instance.
     * @param LicenseManager  $license_manager  License manager instance.
     */
    public function __construct(SettingsManager $settings_manager, LicenseManager $license_manager) {
        $this->settings_manager = $settings_manager;
        $this->license_manager  = $license_manager;

        // Initialize tier matrix if available
        if ( class_exists( TierMatrix::class ) ) {
            $this->tier_matrix = new TierMatrix();
        }
    }

    /**
     * Initialize migration system
     *
     * @return void
     */
    public function init(): void {
        // Check for version changes on admin_init
        add_action( 'admin_init', [ $this, 'check_version' ] );
    }

    /**
     * Check if migration is needed
     *
     * @return void
     */
    public function check_version(): void {
        // Ensure database schema is up to date even if version hasn't changed
        $this->ensure_schema();

        $stored_version  = get_option( self::VERSION_OPTION, '0.0.0' );
        $current_version = PRORANK_VERSION;

        // Skip if versions match
        if ( version_compare( $stored_version, $current_version, '=' ) ) {
            return;
        }

        // Run migrations
        $this->run_migrations( $stored_version, $current_version );

        // Update stored version
        update_option( self::VERSION_OPTION, $current_version );
    }

    /**
     * Run migrations between versions
     *
     * @param string $from_version Previous version.
     * @param string $to_version   Current version.
     * @return void
     */
    private function run_migrations( string $from_version, string $to_version ): void {
        // Get migration history
        $history = get_option( self::MIGRATION_HISTORY_OPTION, [] );

        /**
         * Define migrations
         * Each migration has a version it applies to and a callback
         */
        $migrations = [
            // Example: Tier changes in v0.2.0
            '0.2.0' => [ $this, 'migrate_0_2_0_tier_changes' ],
            // Example: Settings structure change in v0.3.0
            '0.3.0' => [ $this, 'migrate_0_3_0_settings_structure' ],
        ];

        foreach ( $migrations as $version => $callback ) {
            // Skip if this version is not in our upgrade path
            if ( version_compare( $from_version, $version, '>=' ) ) {
                continue;
            }
            if ( version_compare( $to_version, $version, '<' ) ) {
                continue;
            }

            // Skip if already run
            $migration_key = 'migration_' . str_replace( '.', '_', $version );
            if ( isset( $history[ $migration_key ] ) ) {
                continue;
            }

            // Run migration
            try {
                call_user_func( $callback );
                
                // Record success
                $history[ $migration_key ] = [
                    'version'     => $version,
                    'executed_at' => time(),
                    'status'      => 'success',
                ];
                
                // Log migration
                $this->log_migration( "Successfully ran migration for version {$version}" );
                
            } catch ( \Exception $e ) {
                // Record failure
                $history[ $migration_key ] = [
                    'version'     => $version,
                    'executed_at' => time(),
                    'status'      => 'failed',
                    'error'       => $e->getMessage(),
                ];
                
                // Log error
                prorank_log( "ProRank SEO Migration Error ({$version}): " . $e->getMessage() );
            }
        }

        // Update history
        update_option( self::MIGRATION_HISTORY_OPTION, $history );
    }

    /**
     * Ensure critical table schema updates are applied.
     *
     * @return void
     */
    private function ensure_schema(): void {
        global $wpdb;

        $psi_history_table = $wpdb->prefix . 'prorank_psi_history';
        $column = $wpdb->get_var(
            $wpdb->prepare(
                "SHOW COLUMNS FROM {$psi_history_table} LIKE %s",
                'tbt'
            )
        );

        if (null === $column) {
            $wpdb->query("ALTER TABLE {$psi_history_table} ADD COLUMN tbt decimal(10,2) DEFAULT NULL AFTER cls");
        }
    }

    /**
     * Example migration for v0.2.0 tier changes
     *
     * @return void
     */
    private function migrate_0_2_0_tier_changes(): void {
        // Example: Basic Head Cleanup moved from Core to Free
        $this->migrate_feature_to_free_tier( 'technical-seo', 'head_cleanup' );

        // Example: Content Safeguard moved from Core to Free  
        $this->migrate_feature_to_free_tier( 'on-page-seo', 'content_safeguard' );

        // Example: Global Defaults moved from Free to Core
        $this->migrate_feature_from_free_tier( 'titles-meta', 'global_defaults' );
    }

    /**
     * Example migration for v0.3.0 settings structure
     *
     * @return void
     */
    private function migrate_0_3_0_settings_structure(): void {
        // Example of migrating old settings structure to new
        $old_settings = get_option( 'prorank_old_settings', [] );
        
        if ( ! empty( $old_settings ) ) {
            // Map old settings to new structure
            foreach ( $old_settings as $key => $value ) {
                // Determine module and setting key
                $module = $this->determine_module_for_setting( $key );
                $new_key = $this->transform_setting_key( $key );
                
                // Update using settings manager
                $this->settings_manager->update_setting( $module, $new_key, $value );
            }
            
            // Remove old option
            delete_option( 'prorank_old_settings' );
        }
    }

    /**
     * Migrate a feature to free tier
     *
     * @param string $module_slug  Module slug.
     * @param string $feature_slug Feature slug.
     * @return void
     */
    private function migrate_feature_to_free_tier( string $module_slug, string $feature_slug ): void {
        // Get current settings for the feature
        $current_value = $this->settings_manager->get_setting( $module_slug, $feature_slug . '_enabled', null );
        
        // If the feature was previously disabled due to tier restrictions
        // and user's tier was below requirement, enable it now
        if ( false === $current_value ) {
            $current_tier = $this->license_manager->get_current_tier();
            
            // If user is on free tier, enable the feature
            if ( 'free' === $current_tier ) {
                $this->settings_manager->update_setting( $module_slug, $feature_slug . '_enabled', true );
                $this->log_migration( "Enabled {$feature_slug} for free tier users" );
            }
        }
    }

    /**
     * Migrate a feature from free tier to higher tier
     *
     * @param string $module_slug  Module slug.
     * @param string $feature_slug Feature slug.
     * @return void
     */
    private function migrate_feature_from_free_tier( string $module_slug, string $feature_slug ): void {
        // Check user's current tier
        $current_tier = $this->license_manager->get_current_tier();
        
        // If user is on free tier and feature is moving to paid tier
        if ( 'free' === $current_tier ) {
            // Get current setting value
            $current_value = $this->settings_manager->get_setting( $module_slug, $feature_slug . '_enabled', null );
            
            if ( true === $current_value ) {
                // Feature was enabled, now needs to be restricted
                // Keep the setting but add a migration notice
                $notices = $this->settings_manager->get_setting( 'migration', 'tier_change_notices', [] );
                $notices[] = [
                    'feature' => $feature_slug,
                    'module'  => $module_slug,
                    'message' => sprintf(
                        /* translators: %s: feature name */
                        __( 'The %1$s feature now requires a paid plan. Your settings have been preserved and will be available when you upgrade.', 'prorank-seo' ),
                        $this->get_feature_display_name( $module_slug, $feature_slug )
                    ),
                    'date'    => time(),
                ];
                
                $this->settings_manager->update_setting( 'migration', 'tier_change_notices', $notices );
                $this->log_migration( "Feature {$feature_slug} moved to paid tier, settings preserved" );
            }
        }
    }

    /**
     * Determine module for old setting key
     *
     * @param string $old_key Old setting key.
     * @return string Module slug.
     */
    private function determine_module_for_setting( string $old_key ): string {
        // Map old setting prefixes to modules
        $prefix_map = [
            'seo_title_'    => 'titles-meta',
            'sitemap_'      => 'sitemaps',
            'redirect_'     => 'redirects',
            'cache_'        => 'page-caching',
            'schema_'       => 'schema-markup',
            'social_'       => 'social',
            'analytics_'    => 'analytics',
        ];

        foreach ( $prefix_map as $prefix => $module ) {
            if ( str_starts_with( $old_key, $prefix ) ) {
                return $module;
            }
        }

        return 'general';
    }

    /**
     * Transform old setting key to new format
     *
     * @param string $old_key Old setting key.
     * @return string New setting key.
     */
    private function transform_setting_key( string $old_key ): string {
        // Remove module prefix if present
        $prefixes = [ 'seo_title_', 'sitemap_', 'redirect_', 'cache_', 'schema_', 'social_', 'analytics_' ];
        
        foreach ( $prefixes as $prefix ) {
            if ( str_starts_with( $old_key, $prefix ) ) {
                return substr( $old_key, strlen( $prefix ) );
            }
        }

        return $old_key;
    }

    /**
     * Get feature display name
     *
     * @param string $module_slug  Module slug.
     * @param string $feature_slug Feature slug.
     * @return string Display name.
     */
    private function get_feature_display_name( string $module_slug, string $feature_slug ): string {
        // In a real implementation, this would look up proper display names
        $feature_names = [
            'head_cleanup'      => __( 'Head Cleanup', 'prorank-seo' ),
            'content_safeguard' => __( 'Content Safeguard', 'prorank-seo' ),
            'global_defaults'   => __( 'Global Defaults', 'prorank-seo' ),
        ];

        return $feature_names[ $feature_slug ] ?? ucwords( str_replace( [ '-', '_' ], ' ', $feature_slug ) );
    }

    /**
     * Log migration message
     *
     * @param string $message Message to log.
     * @return void
     */
    private function log_migration( string $message ): void {
        if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
            prorank_log( 'ProRank SEO Migration: ' . $message );
        }
    }

    /**
     * Get migration history
     *
     * @return array Migration history.
     */
    public function get_migration_history(): array {
        return get_option( self::MIGRATION_HISTORY_OPTION, [] );
    }

    /**
     * Clear migration history (for testing)
     *
     * @return void
     */
    public function clear_migration_history(): void {
        delete_option( self::MIGRATION_HISTORY_OPTION );
    }
}
