<?php
declare(strict_types=1);

namespace App\Core\Seeder;

use App\Core\Database;

final class SeederRunner
{
    private Database $db;
    private string $seedsDir;

    public function __construct(Database $db)
    {
        $this->db = $db;
        $this->seedsDir = dirname(__DIR__, 2) . '/../database/seeds';
        $this->seedsDir = realpath($this->seedsDir) ?: (dirname(__DIR__, 3) . '/database/seeds');
    }

    public function run(): array
    {
        $this->ensureSeedsTable();
        $executed = $this->getExecutedSeeds();
        $files = $this->getSeedFiles();
        $results = [];

        echo "   Seeds directory: {$this->seedsDir}\n";
        echo "   Found " . count($files) . " seed file(s)\n";
        echo "   Already executed: " . count($executed) . "\n";

        foreach ($files as $file) {
            $name = basename($file, '.php');
            if (in_array($name, $executed)) {
                continue;
            }

            echo "   Seeding: {$name}...\n";

            try {
                $seed = require $file;

                if (is_callable($seed)) {
                    $seed($this->db);
                } elseif (is_object($seed) && method_exists($seed, 'run')) {
                    $seed->run($this->db);
                } else {
                    echo "   ⚠️  Seed {$name} returned non-callable, non-object. Skipping.\n";
                    continue;
                }

                $this->db->insert('seeds', [
                    'seed'        => $name,
                    'executed_at' => date('Y-m-d H:i:s'),
                ]);

                $results[] = $name;
                echo "   ✔ {$name} done\n";
            } catch (\Throwable $e) {
                echo "   ❌ SEED FAILED: {$name} — " . $e->getMessage() . "\n";
                echo "      File: " . $e->getFile() . ":" . $e->getLine() . "\n";
                // Continue to next seed — don't let one failure kill all seeds
            }
        }

        return $results;
    }

    public function runSingle(string $seedName): void
    {
        $this->ensureSeedsTable();
        $files = $this->getSeedFiles();

        $targetFile = null;
        foreach ($files as $file) {
            if (str_contains(basename($file, '.php'), $seedName)) {
                $targetFile = $file;
                break;
            }
        }

        if (!$targetFile) {
            throw new \RuntimeException("Seed not found: {$seedName}");
        }

        $seed = require $targetFile;

        if (is_callable($seed)) {
            $seed($this->db);
        } elseif (is_object($seed) && method_exists($seed, 'run')) {
            $seed->run($this->db);
        }

        $name = basename($targetFile, '.php');
        $existing = $this->db->selectOne("SELECT id FROM seeds WHERE seed = ?", [$name]);
        if (!$existing) {
            $this->db->insert('seeds', [
                'seed'        => $name,
                'executed_at' => date('Y-m-d H:i:s'),
            ]);
        }
    }

    private function ensureSeedsTable(): void
    {
        try {
            $this->db->selectOne("SELECT 1 FROM seeds LIMIT 1");
        } catch (\Throwable $e) {
            $this->db->raw("
                CREATE TABLE IF NOT EXISTS `seeds` (
                    `id` INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
                    `seed` VARCHAR(255) NOT NULL,
                    `executed_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
                    UNIQUE KEY `uq_seeds_name` (`seed`)
                ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
            ");
        }
    }

    private function getExecutedSeeds(): array
    {
        try {
            $rows = $this->db->select("SELECT seed FROM seeds ORDER BY id");
            return array_column($rows, 'seed');
        } catch (\Throwable $e) {
            return [];
        }
    }

    private function getSeedFiles(): array
    {
        if (!is_dir($this->seedsDir)) {
            echo "   ⚠️  Seeds directory not found: {$this->seedsDir}\n";
            return [];
        }

        $files = glob($this->seedsDir . '/Phase_*.php');
        if ($files === false || empty($files)) {
            return [];
        }
        sort($files);
        return $files;
    }
}