<?php

declare(strict_types=1);

namespace App\Console\Commands;

use App\Services\Install\AdminProvisioner;
use App\Services\Install\DbValidator;
use App\Services\Install\EnvChecker;
use App\Services\Install\EnvWriter;
use App\Services\Install\LockGuard;
use App\Services\Install\Migrator;
use App\Services\Install\PasswordPolicy;
use Illuminate\Console\Command;
use Symfony\Component\Yaml\Yaml;

/**
 * CLI 인스톨러 (브라우저 인스톨러의 fallback).
 *
 *   php artisan wdot:install
 *   php artisan wdot:install --non-interactive --config=install.yaml
 *
 * @see /_decisions/INSTALLER_DESIGN.md §4.2
 */
final class WdotInstallCommand extends Command
{
    protected $signature = 'wdot:install
        {--non-interactive : 입력 없이 install.yaml 사용}
        {--config= : install.yaml 경로}';

    protected $description = 'W·Dot CMS 설치 마법사 (CLI fallback)';

    public function handle(
        EnvChecker $env,
        DbValidator $db,
        AdminProvisioner $admin,
        EnvWriter $envWriter,
        Migrator $mig,
        LockGuard $lock,
        PasswordPolicy $policy,
    ): int {
        $this->line('');
        $this->line('  <bg=cyan;fg=white> W·Dot CMS Installer </> v1.0.0');
        $this->line('');

        if ($lock->verify()) {
            $this->error('이미 설치되었습니다. 재설치: `php artisan wdot:reset --force`');

            return self::FAILURE;
        }

        // ----- Stage 1 -----
        $this->info('▶ Stage 1 — 환경 점검');
        $report = $env->run();
        foreach ($report['checks'] as $c) {
            $sym = match ($c['status']) {
                'pass' => '<fg=green>✓</>',
                'warn' => '<fg=yellow>⚠</>',
                default => '<fg=red>✗</>',
            };
            $this->line(sprintf('  %s %-32s %s', $sym, $c['label'], $c['detail']));
        }
        if (! $report['passed']) {
            $this->error('환경 점검 실패. 위 항목을 해결한 뒤 다시 시도하세요.');

            return self::FAILURE;
        }

        // ----- Config: interactive vs YAML -----
        if ($this->option('non-interactive')) {
            $cfgPath = (string) $this->option('config');
            if ($cfgPath === '' || ! is_file($cfgPath)) {
                $this->error('--config 경로가 유효하지 않습니다.');

                return self::FAILURE;
            }
            $cfg = Yaml::parseFile($cfgPath);
            $creds = $cfg['db']    ?? [];
            $adminInput = $cfg['admin'] ?? [];
            $site  = $cfg['site']  ?? [];
        } else {
            // ----- Stage 2 -----
            $this->info("\n▶ Stage 2 — DB 자격");
            $creds = [
                'host'     => $this->ask('DB host', '127.0.0.1'),
                'port'     => (int) $this->ask('DB port', '3306'),
                'database' => $this->ask('DB name', 'wdot_v1'),
                'username' => $this->ask('DB user', 'wdot'),
                'password' => (string) $this->secret('DB password'),
            ];

            // ----- Stage 3 -----
            $this->info("\n▶ Stage 3 — 사이트 + super-admin");
            $site = [
                'app_name' => $this->ask('Site name', 'W·Dot'),
                'app_url'  => $this->ask('Site URL', 'https://localhost'),
                'timezone' => 'Asia/Seoul',
                'locale'   => 'ko',
            ];
            $adminInput = [
                'email' => $this->ask('Admin email'),
                'name'  => $this->ask('Admin name', 'Super Admin'),
            ];
            do {
                $adminInput['password'] = (string) $this->secret('Admin password (12+ chars)');
                $eval = $policy->evaluate($adminInput['password']);
                $this->line('  강도: score '.$eval['score'].'/4 — '.implode(' ', $eval['feedback']));
            } while (! $eval['passed']);
        }

        // Validate DB
        $this->info("\n▶ DB 연결 검증 중...");
        $result = $db->validate($creds);
        if (! $result['ok']) {
            foreach ($result['errors'] as $err) {
                $this->error('  ✗ '.$err);
            }

            return self::FAILURE;
        }
        $this->info('  ✓ DB OK ('.($result['server_version'] ?? 'unknown').')');

        // ----- Stage 4 -----
        $this->info("\n▶ Stage 4 — .env 작성 + 마이그레이션");
        $envWriter->write($creds, $site);
        config([
            'database.connections.mysql.host'     => $creds['host'],
            'database.connections.mysql.port'     => $creds['port'],
            'database.connections.mysql.database' => $creds['database'],
            'database.connections.mysql.username' => $creds['username'],
            'database.connections.mysql.password' => $creds['password'],
        ]);
        \DB::purge('mysql');

        $seedMode = (string) (($cfg ?? [])['seed_mode'] ?? 'basic');
        if (! in_array($seedMode, ['basic', 'demo', 'full'], true)) {
            $seedMode = 'basic';
        }
        $token = $mig->newToken($seedMode);
        $ok = $mig->run($token, $seedMode, function (string $level, string $msg) {
            $this->line('  '.$msg);
        });
        if (! $ok) {
            $this->error('마이그레이션 실패. 로그를 확인하세요.');

            return self::FAILURE;
        }

        // ----- Stage 5 -----
        $this->info("\n▶ Stage 5 — super-admin 생성 + install.lock");
        $created = $admin->provision($adminInput ?? []);
        $path = $lock->create([
            'installer_ip'   => 'CLI',
            'super_admin_id' => $created['user_id'],
            'user_agent'     => 'artisan/'.app()->version(),
        ]);

        $this->newLine();
        $this->line('  <bg=green;fg=white> ✅ 설치 완료 </>');
        $this->line('  install.lock        : '.$path);
        $this->line('  super-admin id      : '.$created['user_id']);
        $this->line('  2FA secret          : '.$created['two_factor_secret']);
        $this->line('  recovery codes      : '.implode(', ', $created['recovery_codes']));
        $this->line('  관리자 URL          : '.rtrim($site['app_url'], '/').'/admin');

        return self::SUCCESS;
    }
}
