<?php

namespace App\Console\Commands;

use App\Services\Installation\InstallationService;
use Illuminate\Console\Command;
use function Laravel\Prompts\text;
use function Laravel\Prompts\select;
use function Laravel\Prompts\confirm;
use function Laravel\Prompts\password;
use function Laravel\Prompts\info;
use function Laravel\Prompts\warning;
use function Laravel\Prompts\error;

class ConfigureCommand extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'ticaga:setup
                            {--mail : Configure outgoing emails only}
                            {--user : Create initial user only}
                            {--app : Configure application settings only}
                            {--skip-on-error : Continue even if a step fails}';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Interactive configuration wizard for Ticaga using Laravel Prompts';

    /**
     * Track if database was configured during setup
     */
    protected bool $databaseConfigured = false;

    /**
     * Execute the console command.
     */
    public function handle()
    {
        // Prevent running if already installed (security measure)
        $installService = new InstallationService();
        if ($installService->isInstalled()) {
            error('✗ Installation already completed!');
            warning('  This command can only be run during initial setup.');
            warning('  To prevent unauthorized access, this command is disabled after installation.');
            $this->newLine();
            return Command::FAILURE;
        }

        info('╔═══════════════════════════════════════════════╗');
        info('║   Ticaga Interactive Configuration Wizard    ║');
        info('╚═══════════════════════════════════════════════╝');
        $this->newLine();

        // Check if any specific flags were provided
        $specificFlags = $this->option('mail') || $this->option('user') || $this->option('app');
        $skipOnError = $this->option('skip-on-error');

        // Database configuration step (before migrations)
        if (confirm(
            label: 'Configure database connection?',
            default: false,
            hint: 'Choose "Yes" to change database settings, or "No" to use install.sh defaults'
        )) {
            $this->runStep('configureDatabase', $skipOnError);
        }

        // Run migrations if needed
        if (!$installService->hasMigrationsTable() || !$installService->hasUsersTable()) {
            info('Database tables not found. Running migrations...');
            $this->call('migrate', ['--force' => true]);
            info('✓ Migrations completed');
            $this->newLine();
        }

        // Run database seeders to set up roles and permissions
        if (!$this->hasRolesSeeded()) {
            info('Setting up roles and permissions...');
            $this->call('db:seed', ['--force' => true]);
            info('✓ Database seeded');
            $this->newLine();
        }

        // If no specific flags, run interactively (ask for each step)
        if (!$specificFlags) {
            if (confirm(
                label: 'Configure outgoing emails?',
                default: true,
                hint: 'Quick SMTP setup for notifications (can be configured via Settings > Mail later)'
            )) {
                $this->runStep('configureMail', $skipOnError);
            }

            if (confirm(
                label: 'Create initial administrator?',
                default: true,
                hint: 'Create your first superadmin user to access the system'
            )) {
                $this->runStep('createUser', $skipOnError);
            }

            if (confirm(
                label: 'Configure application settings?',
                default: true,
                hint: 'Set application name, URL, environment, and debug mode'
            )) {
                $this->runStep('configureApp', $skipOnError);
            }
        } else {
            // Run only the specified steps
            if ($this->option('mail')) {
                $this->runStep('configureMail', $skipOnError);
            }

            if ($this->option('user')) {
                $this->runStep('createUser', $skipOnError);
            }

            if ($this->option('app')) {
                $this->runStep('configureApp', $skipOnError);
            }
        }

        $this->newLine();
        info('✓ Configuration complete!');

        // License configuration step
        if (confirm(
            label: 'License Management?',
            default: true,
            hint: 'Select Yes to obtain a trial license or provide an existing license key'
        )) {
            $this->runStep('configureLicense', $skipOnError);
        }

        // Mark installation as complete to prevent web installer from showing
        $installService = new InstallationService();

        if (!$installService->isInstalled()) {
            $this->newLine();
            info('Marking installation as complete...');

            try {
                $installService->markInstallationComplete();
                info('✓ Installation locked - web installer disabled');
                info('  Lock file created: storage/installed.lock');
            } catch (\Exception $e) {
                $this->newLine();
                error('✗ Failed to create installation lock file!');
                error('  Error: ' . $e->getMessage());
                warning('  The web installer may still be accessible.');
                warning('  Manually create: storage/installed.lock');
                $this->newLine();
                return Command::FAILURE;
            }
        }

        return Command::SUCCESS;
    }

    /**
     * Run a configuration step with optional error handling
     */
    protected function runStep(string $method, bool $skipOnError): void
    {
        try {
            $this->$method();
        } catch (\Exception $e) {
            error("✗ Step failed: {$e->getMessage()}");

            if (!$skipOnError) {
                throw $e;
            }

            warning('⚠ Skipping step due to --skip-on-error flag');
            $this->newLine();
        }
    }

    /**
     * Configure mail settings
     */
    protected function configureMail(): void
    {
        $this->newLine();
        info('━━━ Outgoing Email Configuration ━━━');

        $mailDriver = select(
            label: 'Mail driver',
            options: [
                'smtp' => 'SMTP',
                'sendmail' => 'Sendmail',
                'mailgun' => 'Mailgun',
                'ses' => 'Amazon SES',
            ],
            default: config('mail.default', 'smtp')
        );

        if ($mailDriver === 'smtp') {
            $host = text(
                label: 'SMTP Host',
                placeholder: 'smtp.gmail.com',
                default: config('mail.mailers.smtp.host', 'localhost'),
                required: true
            );

            $port = text(
                label: 'SMTP Port',
                default: (string) config('mail.mailers.smtp.port', '587'),
                validate: fn($value) => is_numeric($value) ? null : 'Port must be numeric'
            );

            $username = text(
                label: 'SMTP Username',
                placeholder: 'your-email@example.com',
                default: config('mail.mailers.smtp.username', ''),
                required: true
            );

            $password = password(
                label: 'SMTP Password',
                required: true
            );

            $encryption = select(
                label: 'Encryption',
                options: ['tls' => 'TLS', 'ssl' => 'SSL', 'none' => 'None'],
                default: config('mail.mailers.smtp.encryption', 'tls')
            );

            $fromAddress = text(
                label: 'From Email Address',
                placeholder: 'support@example.com',
                default: config('mail.from.address', ''),
                required: true,
                validate: fn($value) => filter_var($value, FILTER_VALIDATE_EMAIL)
                    ? null : 'Invalid email address'
            );

            $fromName = text(
                label: 'From Name',
                placeholder: 'Ticaga Support',
                default: config('mail.from.name', config('app.name')),
                required: true
            );

            // Update .env file
            info('Updating mail configuration...');
            $this->updateEnv([
                'MAIL_MAILER' => $mailDriver,
                'MAIL_HOST' => $host,
                'MAIL_PORT' => $port,
                'MAIL_USERNAME' => $username,
                'MAIL_PASSWORD' => $password,
                'MAIL_ENCRYPTION' => $encryption === 'none' ? '' : $encryption,
                'MAIL_FROM_ADDRESS' => $fromAddress,
                'MAIL_FROM_NAME' => '"' . $fromName . '"',
            ]);

            info('✓ Mail configuration saved');
        }
    }

    /**
     * Create initial user
     */
    protected function createUser(): void
    {
        $this->newLine();
        info('━━━ Create Administrator User ━━━');

        $name = text(
            label: 'Full Name',
            placeholder: 'John Doe',
            required: true
        );

        $email = text(
            label: 'Email Address',
            placeholder: 'admin@example.com',
            required: true,
            validate: fn($value) => filter_var($value, FILTER_VALIDATE_EMAIL)
                ? null : 'Invalid email address'
        );

        $password = password(
            label: 'Password',
            required: true,
            validate: fn($value) => strlen($value) >= 8
                ? null : 'Password must be at least 8 characters'
        );

        $passwordConfirm = password(
            label: 'Confirm Password',
            required: true,
            validate: fn($value) => $value === $password
                ? null : 'Passwords do not match'
        );

        info('Creating superadmin user...');
        $user = \App\Models\User::create([
            'name' => $name,
            'email' => $email,
            'password' => bcrypt($password),
        ]);

        // Ensure superadmin role exists with proper guard, then assign it
        $role = \Spatie\Permission\Models\Role::firstOrCreate(
            ['name' => 'superadmin', 'guard_name' => 'web']
        );
        $user->assignRole($role);

        // Verify role assignment
        if ($user->hasRole('superadmin')) {
            info("✓ Superadmin user created: $email");
            info("  Role assigned: superadmin");
        } else {
            error("✗ User created but role assignment failed!");
            warning("  Please manually assign superadmin role in the database");
        }
    }

    /**
     * Configure application settings
     */
    protected function configureApp(): void
    {
        $this->newLine();
        info('━━━ Application Settings ━━━');

        $appName = text(
            label: 'Application Name',
            default: config('app.name', 'Ticaga'),
            required: true
        );

        $appUrl = text(
            label: 'Application URL',
            placeholder: 'https://support.example.com',
            default: config('app.url', ''),
            required: true,
            validate: fn($value) => filter_var($value, FILTER_VALIDATE_URL)
                ? null : 'Invalid URL'
        );

        // Automatically set to production (advanced users can change in .env later)
        $appEnv = 'production';
        info('Environment set to: Production');

        $appDebug = confirm(
            label: 'Enable debug mode?',
            default: false,
            hint: 'Only enable for development/troubleshooting (NOT recommended for production)'
        );

        if ($appDebug) {
            warning('⚠ Debug mode should not be enabled in production!');
            $appDebug = confirm('Are you sure you want to enable debug mode?', default: false);
        }

        info('Updating application settings...');
        $this->updateEnv([
            'APP_NAME' => '"' . $appName . '"',
            'APP_URL' => $appUrl,
            'APP_ENV' => $appEnv,
            'APP_DEBUG' => $appDebug ? 'true' : 'false',
        ]);

        info('✓ Application settings saved');
    }

    /**
     * Configure database connection
     */
    protected function configureDatabase(): void
    {
        $this->newLine();
        info('━━━ Database Configuration ━━━');

        $useExisting = confirm(
            'Use existing database configuration from install.sh?',
            default: true,
            hint: 'Choose "No" to configure manually'
        );

        if ($useExisting) {
            info('✓ Using existing database configuration');
            $this->databaseConfigured = false;
            return;
        }

        $dbConnection = select(
            label: 'Database Connection',
            options: [
                'mysql' => 'MySQL',
                'pgsql' => 'PostgreSQL',
                'sqlite' => 'SQLite',
            ],
            default: config('database.default', 'mysql')
        );

        if ($dbConnection === 'sqlite') {
            $dbDatabase = text(
                label: 'Database File Path',
                default: database_path('database.sqlite'),
                required: true
            );

            info('Updating database configuration...');
            $this->updateEnv([
                'DB_CONNECTION' => $dbConnection,
                'DB_DATABASE' => $dbDatabase,
            ]);

            // Create SQLite database file if it doesn't exist
            if (!file_exists($dbDatabase)) {
                touch($dbDatabase);
                info('✓ SQLite database file created');
            }
        } else {
            $dbHost = text(
                label: 'Database Host',
                default: config('database.connections.mysql.host', 'localhost'),
                required: true
            );

            $dbPort = text(
                label: 'Database Port',
                default: (string) config('database.connections.mysql.port', '3306'),
                validate: fn($value) => is_numeric($value) ? null : 'Port must be numeric'
            );

            $dbDatabase = text(
                label: 'Database Name',
                default: config('database.connections.mysql.database', 'ticaga'),
                required: true
            );

            $dbUsername = text(
                label: 'Database Username',
                default: config('database.connections.mysql.username', 'root'),
                required: true
            );

            $dbPassword = password(
                label: 'Database Password',
                required: false
            );

            info('Updating database configuration...');
            $this->updateEnv([
                'DB_CONNECTION' => $dbConnection,
                'DB_HOST' => $dbHost,
                'DB_PORT' => $dbPort,
                'DB_DATABASE' => $dbDatabase,
                'DB_USERNAME' => $dbUsername,
                'DB_PASSWORD' => $dbPassword,
            ]);
        }

        info('✓ Database configuration saved');
        $this->databaseConfigured = true;

        // Test database connection
        info('Testing database connection...');
        try {
            \DB::reconnect();
            \DB::connection()->getPdo();
            info('✓ Database connection successful');
        } catch (\Exception $e) {
            error('✗ Database connection failed: ' . $e->getMessage());
            warning('  Please verify your database settings and try again.');
            throw $e;
        }
    }

    /**
     * Configure license key
     */
    protected function configureLicense(): void
    {
        $this->newLine();
        info('━━━ License Configuration ━━━');

        $licenseOption = select(
            label: 'License Option',
            options: [
                'trial' => 'Free trial',
                'enter' => 'Enter license key',
            ],
            default: 'trial'
        );

        if ($licenseOption === 'trial') {
            info('Requesting trial license from Blesta License Manager...');
            info('This may take a few moments...');

            try {
                // Use the Controller trial function
                $licenseResponse = \App\Http\Controllers\Controller::trial();

                if (empty($licenseResponse)) {
                    error('✗ Trial license request returned empty response');
                    warning('  Please try again or enter a license key manually.');
                    return;
                }

                // Parse JSON response if needed
                $licenseKey = $licenseResponse;
                if (is_string($licenseResponse) && str_starts_with($licenseResponse, '{')) {
                    $decoded = json_decode($licenseResponse, true);
                    if (json_last_error() === JSON_ERROR_NONE && isset($decoded['key'])) {
                        $licenseKey = $decoded['key'];

                        // Show status if present
                        if (isset($decoded['status'])) {
                            info("  Status: {$decoded['status']}");
                        }
                    }
                }

                // Store in .env
                $this->updateEnv([
                    'LICENSE_KEY' => $licenseKey,
                ]);

                info('✓ Trial license obtained and saved to .env!');
                info("  License Key: {$licenseKey}");
                info('  Trial licenses are valid for 14 days.');

            } catch (\RuntimeException $e) {
                error('✗ Failed to obtain trial license');
                error('  Error: ' . $e->getMessage());
                warning('  You can add a license key later in Settings > License.');
                warning('  Or run this command again to retry.');

                // Ask if they want to enter manually
                if (confirm('Would you like to enter a license key manually?', default: false)) {
                    $this->enterLicenseKeyManually();
                }
            }

        } elseif ($licenseOption === 'enter') {
            $this->enterLicenseKeyManually();
        }
    }

    /**
     * Prompt for manual license key entry
     */
    protected function enterLicenseKeyManually(): void
    {
        $licenseKey = text(
            label: 'License Key',
            placeholder: 'Enter your Ticaga license key',
            required: true,
            validate: fn($value) => strlen($value) >= 10
                ? null : 'License key must be at least 10 characters'
        );

        // Store in .env
        $this->updateEnv([
            'LICENSE_KEY' => $licenseKey,
        ]);

        info('✓ License key saved to .env successfully!');
        info('  Validating license...');

        try {
            // Validate license
            $status = \App\Http\Controllers\Controller::checkStatus();

            if ($status['status'] === 'active') {
                info('✓ License validated successfully!');
            } else {
                warning('⚠ License validation returned: ' . $status['status']);
                warning('  Message: ' . $status['msg']);
                warning('  Your installation will continue, but features may be limited.');
            }
        } catch (\Exception $e) {
            warning('⚠ Unable to validate license at this time');
            warning('  Error: ' . $e->getMessage());
            warning('  Your installation will continue. License will be validated on first use.');
        }
    }

    /**
     * Check if roles have been seeded
     */
    protected function hasRolesSeeded(): bool
    {
        try {
            // Check if the roles table exists and has the superadmin role
            return \DB::table('roles')->where('name', 'superadmin')->exists();
        } catch (\Exception $e) {
            // Table doesn't exist yet
            return false;
        }
    }

    /**
     * Update .env file with new values
     */
    protected function updateEnv(array $data): void
    {
        $envPath = base_path('.env');

        if (!file_exists($envPath)) {
            error('⚠ .env file not found');
            return;
        }

        $env = file_get_contents($envPath);

        foreach ($data as $key => $value) {
            // Replace existing value or append if not found
            if (preg_match("/^{$key}=.*/m", $env)) {
                $env = preg_replace("/^{$key}=.*/m", "{$key}={$value}", $env);
            } else {
                $env .= "\n{$key}={$value}";
            }
        }

        file_put_contents($envPath, $env);
    }
}
