<?php

namespace App\Database;

use App\Core\Database;

/**
 * ITSWEBER CMS – Migration Runner
 *
 * Discovers and executes migration files in order.
 * Tracks executed migrations in iw_migrations table to avoid re-execution.
 * Falls back to idempotent full-run if tracking table does not exist.
 */
class Migrator
{
    private Database $db;
    private string $migrationsPath;

    public function __construct(Database $db, string $migrationsPath)
    {
        $this->db = $db;
        $this->migrationsPath = $migrationsPath;
    }

    /**
     * Run all pending migrations.
     * Creates the tracking table if it does not exist, then skips already-executed files.
     */
    public function runAll(): array
    {
        $this->ensureTrackingTable();

        $executed = $this->getExecuted();
        $files    = glob($this->migrationsPath . '/*.php');
        sort($files);

        $results = [];
        foreach ($files as $file) {
            $basename = basename($file);

            // Skip already-executed migrations
            if (in_array($basename, $executed, true)) {
                continue;
            }

            $className = $this->getClassName($file);
            require_once $file;

            $fullClass = 'App\\Database\\Migrations\\' . $className;
            if (!class_exists($fullClass)) {
                $fullClass = $className;
            }

            $migration = new $fullClass($this->db);
            $migration->up();

            $this->recordMigration($basename);
            $results[] = $basename;
        }

        return $results;
    }

    /**
     * Create the migrations tracking table if it does not exist.
     */
    private function ensureTrackingTable(): void
    {
        $this->db->query("
            CREATE TABLE IF NOT EXISTS iw_migrations (
                id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
                migration VARCHAR(255) NOT NULL UNIQUE,
                executed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
            ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
        ");
    }

    /**
     * Get list of already-executed migration filenames.
     */
    private function getExecuted(): array
    {
        try {
            $rows = $this->db->fetchAll("SELECT migration FROM iw_migrations ORDER BY id");
            return array_column($rows, 'migration');
        } catch (\Exception $e) {
            return [];
        }
    }

    /**
     * Record a migration as executed.
     */
    private function recordMigration(string $filename): void
    {
        $this->db->query(
            "INSERT IGNORE INTO iw_migrations (migration) VALUES (:file)",
            ['file' => $filename]
        );
    }

    /**
     * Extract class name from migration file.
     *
     * Supports two naming conventions:
     *   - PascalCase: class AddFeaturedPosts extends Migration
     *   - Prefixed:   class Migration_052_add_stats (no extends)
     *
     * First tries the PascalCase convention derived from filename.
     * If the class doesn't exist after require, scans the file for the
     * actual class declaration.
     */
    private function getClassName(string $file): string
    {
        // Convention 1: PascalCase from filename (e.g. 051_add_featured → AddFeatured)
        $filename = pathinfo($file, PATHINFO_FILENAME);
        $name = preg_replace('/^\d+_/', '', $filename);
        $pascalName = str_replace('_', '', ucwords($name, '_'));

        // If file is already loaded and PascalCase class exists, use it
        if (class_exists($pascalName, false)) {
            return $pascalName;
        }

        // Convention 2: scan file for actual class name (handles Migration_NNN_... pattern)
        $content = file_get_contents($file);
        if ($content !== false && preg_match('/^\s*class\s+(\S+)/m', $content, $m)) {
            $actualClass = $m[1];
            if ($actualClass !== $pascalName) {
                return $actualClass;
            }
        }

        return $pascalName;
    }
}
