<?php

namespace Database\Seeders;

// use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;

class DatabaseSeeder extends Seeder
{
    /**
     * Available seeders with descriptions.
     */
    private array $availableSeeders = [];

    public function __construct()
    {
        $this->discoverSeeders();
    }

    /**
     * Automatically discover all seeders in the database/seeders directory.
     */
    private function discoverSeeders(): void
    {
        $seederPath = database_path('seeders');
        $seederFiles = glob($seederPath.'/*Seeder.php');

        foreach ($seederFiles as $file) {
            $className = basename($file, '.php');
            $fullClassName = "Database\\Seeders\\{$className}";

            // Skip DatabaseSeeder itself to avoid recursion
            if ($className === 'DatabaseSeeder') {
                continue;
            }

            // Check if class exists and is instantiable
            if (class_exists($fullClassName) && is_subclass_of($fullClassName, Seeder::class)) {
                $this->availableSeeders[$className] = [
                    'class' => $fullClassName,
                    'description' => $this->generateSeederDescription($className),
                    'default' => $this->getDefaultSelection($className),
                ];
            }
        }
    }

    /**
     * Generate description for seeder based on its name.
     */
    private function generateSeederDescription(string $className): string
    {
        // Common patterns for seeder descriptions
        $descriptions = [
            'AdminSeeder' => 'Create admin user with interactive password prompt',
            'MetaSeeder' => 'Seed meta tags and SEO data',
            'NewSettingsSeeder' => 'Seed Filament settings (website, IMAP, configuration)',
            'UserSeeder' => 'Seed sample users',
            'PlanSeeder' => 'Seed subscription plans',
            'CategorySeeder' => 'Seed categories',
            'PostSeeder' => 'Seed blog posts',
            'ProductSeeder' => 'Seed products',
            'OrderSeeder' => 'Seed sample orders',
            'PermissionSeeder' => 'Seed permissions and roles',
            'CountrySeeder' => 'Seed countries data',
            'LanguageSeeder' => 'Seed languages data',
            'CurrencySeeder' => 'Seed currencies data',
            'PaymentSeeder' => 'Seed payment methods and data',
            'PaymentProviderSeeder' => 'Seed payment providers (Stripe, Lemon Squeezy, Polar, etc.)',
            'EmailSeeder' => 'Seed email templates',
            'NotificationSeeder' => 'Seed notification templates',
            'SettingsSeeder' => 'Seed application settings',
            'TestSeeder' => 'Seed test data',
            'DemoSeeder' => 'Seed demo data',
            'SampleSeeder' => 'Seed sample data',
        ];

        if (isset($descriptions[$className])) {
            return $descriptions[$className];
        }

        // Generate description based on class name pattern
        $name = strtolower(str_replace('Seeder', '', $className));

        // Simple pluralization
        if (str_ends_with($name, 'y')) {
            $name = substr($name, 0, -1).'ies';
        } elseif (! str_ends_with($name, 's')) {
            $name .= 's';
        }

        return "Seed {$name}";
    }

    /**
     * Determine if a seeder should be selected by default.
     */
    private function getDefaultSelection(string $className): bool
    {
        // Core/essential seeders that should run by default
        $essentialSeeders = [
            'AdminSeeder',
            'NewSettingsSeeder',
            'SettingsSeeder',
            'MetaSeeder',
        ];

        return in_array($className, $essentialSeeders);
    }

    /**
     * Seed the application's database.
     */
    public function run(): void
    {
        $this->command->info('🌱 Welcome to Interactive Database Seeder!');
        $this->command->info('');
        $this->command->info('Use arrow keys to navigate, spacebar to toggle selection, Enter to run:');
        $this->command->info('');

        $selectedSeeders = $this->runInteractiveSelection();

        if (empty($selectedSeeders)) {
            $this->command->warn('❌ No seeders selected. Exiting...');

            return;
        }

        $this->command->info('');
        $this->command->info('🚀 Running '.count($selectedSeeders).' selected seeders:');

        // Run selected seeders
        foreach ($selectedSeeders as $seederName) {
            $seederInfo = $this->availableSeeders[$seederName];
            $this->command->info("  📦 Running {$seederName}...");

            try {
                $this->call($seederInfo['class']);
                $this->command->info("    ✅ {$seederName} completed successfully");
            } catch (\Exception $e) {
                $this->command->error("    ❌ {$seederName} failed: {$e->getMessage()}");
            }
        }

        $this->command->info('');
        $this->command->info('🎉 Database seeding completed!');
    }

    /**
     * Run interactive checkbox selection.
     */
    private function runInteractiveSelection(): array
    {
        // Initialize selection with defaults
        $selection = [];
        foreach ($this->availableSeeders as $name => $info) {
            $selection[$name] = $info['default'];
        }

        $seederNames = array_keys($this->availableSeeders);
        $currentIndex = 0;

        // Check if we're on Windows or have limited terminal capabilities
        if ($this->isWindows() || ! $this->supportsInteractiveTerminal()) {
            return $this->runFallbackSelection($seederNames, $selection);
        }

        // Set up terminal for interactive input (Unix-like systems)
        if (function_exists('readline_callback_handler_install')) {
            readline_callback_handler_install('', function () {});
        }

        // Set terminal to raw mode for character input
        shell_exec('stty -icanon -echo');

        try {
            while (true) {
                // Clear screen and redraw
                $this->clearScreen();
                $this->displayCheckboxInterface($seederNames, $currentIndex, $selection);

                // Read single character
                $read = [STDIN];
                $write = [];
                $except = [];
                $n = stream_select($read, $write, $except, null);

                if ($n && in_array(STDIN, $read)) {
                    $char = fgetc(STDIN);

                    switch ($char) {
                        case "\033": // Escape sequence (arrow keys)
                            $this->handleArrowKey($currentIndex, $seederNames, $currentIndex);
                            break;

                        case ' ': // Spacebar - toggle selection
                            $currentSeeder = $seederNames[$currentIndex];
                            $selection[$currentSeeder] = ! $selection[$currentSeeder];
                            break;

                        case "\n": // Enter - confirm selection
                        case "\r":
                            $this->restoreTerminal();
                            if (function_exists('readline_callback_handler_remove')) {
                                readline_callback_handler_remove();
                            }

                            return array_keys(array_filter($selection));

                        case 'a': // Select all
                        case 'A':
                            foreach ($selection as $key => $value) {
                                $selection[$key] = true;
                            }
                            break;

                        case 'n': // Select none
                        case 'N':
                            foreach ($selection as $key => $value) {
                                $selection[$key] = false;
                            }
                            break;

                        case 'q': // Quit
                        case 'Q':
                        case "\x03": // Ctrl+C
                            $this->restoreTerminal();
                            if (function_exists('readline_callback_handler_remove')) {
                                readline_callback_handler_remove();
                            }

                            return [];
                    }
                }
            }
        } finally {
            $this->restoreTerminal();
            if (function_exists('readline_callback_handler_remove')) {
                readline_callback_handler_remove();
            }
        }
    }

    /**
     * Handle arrow key sequences.
     */
    private function handleArrowKey(int &$currentIndex, array $seederNames, int &$newIndex): void
    {
        // Read the next two characters of the escape sequence
        $char1 = fgetc(STDIN);
        $char2 = fgetc(STDIN);

        if ($char1 === '[') {
            switch ($char2) {
                case 'A': // Up arrow
                    $currentIndex = max(0, $currentIndex - 1);
                    break;
                case 'B': // Down arrow
                    $currentIndex = min(count($seederNames) - 1, $currentIndex + 1);
                    break;
            }
        }

        $newIndex = $currentIndex;
    }

    /**
     * Display the checkbox interface.
     */
    private function displayCheckboxInterface(array $seederNames, int $currentIndex, array $selection): void
    {
        $this->command->info('┌─────────────────────────────────────────────────────────────┐');
        $this->command->info('│                    Select Seeders                          │');
        $this->command->info('│                                                             │');
        $this->command->info('│  ↑↓ : Navigate   Space : Toggle   A : All   N : None      │');
        $this->command->info('│  Enter : Run   Q : Quit                                      │');
        $this->command->info('└─────────────────────────────────────────────────────────────┘');
        $this->command->info('');

        foreach ($seederNames as $index => $seederName) {
            $info = $this->availableSeeders[$seederName];
            $isSelected = $selection[$seederName];
            $isCurrent = $index === $currentIndex;

            $checkbox = $isSelected ? '✅' : '⭕';
            $marker = $isCurrent ? '►' : ' ';
            $description = $info['description'];

            // Truncate description if too long
            if (strlen($description) > 50) {
                $description = substr($description, 0, 47).'...';
            }

            $line = sprintf('  %s %s %-20s %s', $marker, $checkbox, $seederName, $description);

            if ($isCurrent) {
                $this->command->line($line);
            } else {
                $this->command->info($line);
            }
        }

        $this->command->info('');
        $selectedCount = count(array_filter($selection));
        $totalCount = count($seederNames);
        $this->command->info("Selected: {$selectedCount}/{$totalCount} seeders");
    }

    /**
     * Clear the terminal screen.
     */
    private function clearScreen(): void
    {
        // ANSI escape code to clear screen and move cursor to top-left
        echo "\033[2J\033[H";
    }

    /**
     * Check if running on Windows.
     */
    private function isWindows(): bool
    {
        return strtoupper(substr(PHP_OS, 0, 3)) === 'WIN';
    }

    /**
     * Check if terminal supports interactive features.
     */
    private function supportsInteractiveTerminal(): bool
    {
        return function_exists('shell_exec') && shell_exec('which stty') !== null;
    }

    /**
     * Restore terminal settings.
     */
    private function restoreTerminal(): void
    {
        if (! $this->isWindows() && $this->supportsInteractiveTerminal()) {
            shell_exec('stty icanon echo');
        }
    }

    /**
     * Fallback selection method for Windows or limited terminals.
     */
    private function runFallbackSelection(array $seederNames, array $selection): array
    {
        $this->command->info('🌱 Available Seeders (Windows/Basic Mode):');
        $this->command->info('');

        foreach ($seederNames as $index => $seederName) {
            $info = $this->availableSeeders[$seederName];
            $isSelected = $selection[$seederName];
            $status = $isSelected ? '✅' : '⭕';
            $description = $info['description'];

            if (strlen($description) > 50) {
                $description = substr($description, 0, 47).'...';
            }

            $this->command->line(sprintf('  [%d] %s %s - %s', $index + 1, $status, $seederName, $description));
        }

        $this->command->info('');
        $this->command->info('Options:');
        $this->command->line('  • Enter numbers (e.g., "1 3 5") to toggle selection');
        $this->command->line('  • Type "all" to select all');
        $this->command->line('  • Type "none" to deselect all');
        $this->command->line('  • Type "list" to show current selection');
        $this->command->line('  • Press Enter to run selected seeders');
        $this->command->line('  • Type "exit" to cancel');
        $this->command->info('');

        while (true) {
            $input = trim($this->command->ask('Enter your choice (or press Enter to run)'));

            if (empty($input)) {
                break; // Run with current selection
            }

            $input = strtolower($input);

            switch ($input) {
                case 'exit':
                case 'quit':
                    $this->command->warn('👋 Exiting seeder...');

                    return [];

                case 'all':
                    foreach ($selection as $key => $value) {
                        $selection[$key] = true;
                    }
                    $this->displayCurrentSelection($selection);
                    break;

                case 'none':
                    foreach ($selection as $key => $value) {
                        $selection[$key] = false;
                    }
                    $this->displayCurrentSelection($selection);
                    break;

                case 'list':
                    $this->displayCurrentSelection($selection);
                    break;

                default:
                    // Toggle by numbers
                    $numbers = preg_split('/\s+/', $input);
                    $toggled = false;

                    foreach ($numbers as $num) {
                        if (is_numeric($num)) {
                            $index = (int) $num - 1;
                            if (isset($seederNames[$index])) {
                                $seederName = $seederNames[$index];
                                $selection[$seederName] = ! $selection[$seederName];
                                $status = $selection[$seederName] ? 'selected' : 'deselected';
                                $this->command->line("  ✓ {$seederName} {$status}");
                                $toggled = true;
                            }
                        }
                    }

                    if (! $toggled) {
                        $this->command->warn("  ⚠️  Invalid input: {$input}");
                        $this->command->line('  Try numbers (1, 2, 3) or commands: all, none, list, exit');
                    }
                    break;
            }
        }

        return array_keys(array_filter($selection));
    }

    /**
     * Display current selection for fallback mode.
     */
    private function displayCurrentSelection(array $selection): void
    {
        $selected = array_keys(array_filter($selection));
        if (empty($selected)) {
            $this->command->line('  ⭕ No seeders selected');
        } else {
            $this->command->line('  ✅ Selected: '.implode(', ', $selected));
        }
    }

    /**
     * Display current selection.
     */
    private function displaySelection(array $selected): void
    {
        if (empty($selected)) {
            $this->command->line('  ⭕ No seeders selected');
        } else {
            $this->command->line('  ✅ Currently selected: '.implode(', ', $selected));
        }
    }
}
