<?php
declare(strict_types=1);
// ==================================================
// Nuclear Fancy Pants Edition™ — NUCLEAR+++
// File: /includes/class-migration-runner.php
// Description: Forward-only versioned migration runner for AutoMarketer AI WP plugin - NUCLEAR+++
// Last Edited: 2026-04-22
// ==================================================

namespace AutoMarketerAI;

// No direct access
defined('ABSPATH') || exit;

final class MigrationRunner
{
    // wp_options key that tracks applied migration versions
    private const APPLIED_OPTION = 'amai_applied_migrations';

    // Ordered list of all migrations. Add new entries at the bottom only.
    // Key: version string. Value: fully-qualified class name.
    private const MIGRATIONS = [
        '001' => \AutoMarketerAI\Migrations\Migration_001_BusinessProfileAndFacebookConnection::class,
        '002' => \AutoMarketerAI\Migrations\Migration_002_ScheduledPosts::class,
        '003' => \AutoMarketerAI\Migrations\Migration_003_ScheduledPostsUtc::class,
        '004' => \AutoMarketerAI\Migrations\Migration_004_BusinessProfileTimezone::class,
        '005' => \AutoMarketerAI\Migrations\Migration_005_Waitlist::class,
        '006' => \AutoMarketerAI\Migrations\Migration_006_MediaLocationFeeling::class,
        '007' => \AutoMarketerAI\Migrations\Migration_007_UnsplashImage::class,
        '008' => \AutoMarketerAI\Migrations\Migration_008_BatchUniqueKey::class,
        '009' => \AutoMarketerAI\Migrations\Migration_009_InstagramAccountId::class,
        '010' => \AutoMarketerAI\Migrations\Migration_010_ChannelColumn::class,
        '011' => \AutoMarketerAI\Migrations\Migration_011_PostStats::class,
        '012' => \AutoMarketerAI\Migrations\Migration_012_BusinessProfileFacebookBio::class,
        '013' => \AutoMarketerAI\Migrations\Migration_013_PostTypeEnumExpand::class,
        '014' => \AutoMarketerAI\Migrations\Migration_014_LinkedInConnection::class,
        '015' => \AutoMarketerAI\Migrations\Migration_015_TikTokConnection::class,
        '016' => \AutoMarketerAI\Migrations\Migration_016_XConnection::class,
        '017' => \AutoMarketerAI\Migrations\Migration_017_GenerationBatchWidth::class,
        '018' => \AutoMarketerAI\Migrations\Migration_018_BouncesTable::class,
        '019' => \AutoMarketerAI\Migrations\Migration_019_GoogleConnection::class,
        '020' => \AutoMarketerAI\Migrations\Migration_020_AbandonedCarts::class,
        '021' => \AutoMarketerAI\Migrations\Migration_021_AbandonedCartsRawTotal::class,
        '022' => \AutoMarketerAI\Migrations\Migration_022_AbandonedCartsSequence::class,
        '023' => \AutoMarketerAI\Migrations\Migration_023_CompetitorRadar::class,
        '024' => \AutoMarketerAI\Migrations\Migration_024_BlogSchedule::class,
        '025' => \AutoMarketerAI\Migrations\Migration_025_EmailContacts::class,
        '026' => \AutoMarketerAI\Migrations\Migration_026_NudgeLog::class,
        '027' => \AutoMarketerAI\Migrations\Migration_027_OutboundLinks::class,
        '028' => \AutoMarketerAI\Migrations\Migration_028_AbandonedCartsUnsubToken::class,
        '029' => \AutoMarketerAI\Migrations\Migration_029_AbandonedCartsPhone::class,
        '030' => \AutoMarketerAI\Migrations\Migration_030_UsermetaIsolation::class,
        '031' => \AutoMarketerAI\Migrations\Migration_031_EncryptApiKeys::class,
        '032' => \AutoMarketerAI\Migrations\Migration_032_NudgeLogDismissed::class,
        '033' => \AutoMarketerAI\Migrations\Migration_033_ScheduledPostsPlatformIds::class,
        '034' => \AutoMarketerAI\Migrations\Migration_034_SocialComments::class,
        '035' => \AutoMarketerAI\Migrations\Migration_035_WpCommentId::class,
        '036' => \AutoMarketerAI\Migrations\Migration_036_CommentForm::class,
        '037' => \AutoMarketerAI\Migrations\Migration_037_ProductCatalog::class,
        '038' => \AutoMarketerAI\Migrations\Migration_038_ProductViews::class,
        '039' => \AutoMarketerAI\Migrations\Migration_039_DropWaitlist::class,
        '040' => \AutoMarketerAI\Migrations\Migration_040_GoogleReviews::class,
        '041' => \AutoMarketerAI\Migrations\Migration_041_CompetitorUrls::class,
        '042' => \AutoMarketerAI\Migrations\Migration_042_GapTopicQueue::class,
        '043' => \AutoMarketerAI\Migrations\Migration_043_Ga4Connection::class,
        '044' => \AutoMarketerAI\Migrations\Migration_044_Ga4Metrics::class,
        '045' => \AutoMarketerAI\Migrations\Migration_045_Clusters::class,
        '046' => \AutoMarketerAI\Migrations\Migration_046_CommentSentiment::class,
        '047' => \AutoMarketerAI\Migrations\Migration_047_PinterestConnection::class,
    ];

    // Run all pending migrations in order
    public function run(): void
    {
        $applied = $this->getApplied();

        foreach (self::MIGRATIONS as $version => $class) {
            if (in_array($version, $applied, true)) {
                continue;
            }

            if (!class_exists($class)) {
                // Hard fail — a missing migration class is a deployment error
                wp_die(
                    esc_html(
                        sprintf(
                            '[AutoMarketer AI] Migration %s class not found: %s',
                            $version,
                            $class
                        )
                    )
                );
            }

            $migration = new $class();
            $migration->up();

            $applied[] = $version;
            $this->saveApplied($applied);
        }
    }

    // Returns the list of applied migration version strings
    private function getApplied(): array
    {
        $raw = get_option(self::APPLIED_OPTION, '');

        if (!is_string($raw) || $raw === '') {
            return [];
        }

        $decoded = json_decode($raw, true);

        if (!is_array($decoded)) {
            return [];
        }

        return array_values(array_filter($decoded, 'is_string'));
    }

    // Persists the applied version list to wp_options
    private function saveApplied(array $applied): void
    {
        update_option(self::APPLIED_OPTION, wp_json_encode($applied), false);
    }

    // Returns true if all known migrations have been applied
    public function isUpToDate(): bool
    {
        $applied = $this->getApplied();
        $pending = array_diff(array_keys(self::MIGRATIONS), $applied);

        return count($pending) === 0;
    }

    // Returns version strings of migrations not yet applied
    public function getPending(): array
    {
        $applied = $this->getApplied();

        return array_values(array_diff(array_keys(self::MIGRATIONS), $applied));
    }
}