#!/usr/bin/env php
<?php
declare(strict_types=1);

require_once __DIR__ . '/../vendor/autoload.php';

use Fendx\Cli\Application;
use Fendx\Cli\Command\VersionCommand;
use Fendx\Cli\Command\HelpCommand;
use Fendx\Cli\Command\ServerCommand;
use Fendx\Cli\Command\MigrateCommand;
use Fendx\Cli\Command\GenerateCommand;

/**
 * FendxPHP 控制台应用
 */
class ConsoleApplication extends Application
{
    protected function getDefaultCommands(): array
    {
        return [
            new VersionCommand(),
            new HelpCommand(),
            new ServerCommand(),
            new MigrateCommand(),
            new GenerateCommand(),
            new TestCommand(),
            new DeployCommand(),
            new BenchmarkCommand(),
        ];
    }
}

/**
 * 测试命令
 */
class TestCommand extends \Fendx\Cli\Command\Command
{
    protected function configure(): void
    {
        $this->setName('test')
            ->setDescription('运行测试套件')
            ->addArgument('type', '测试类型: unit, integration, api, e2e, performance, security')
            ->addOption('filter', 'f', '过滤测试用例')
            ->addOption('coverage', 'c', '生成覆盖率报告')
            ->addOption('parallel', 'p', '并行测试', false, 4);
    }

    protected function execute(\Fendx\Cli\Input\InputInterface $input, \Fendx\Cli\Output\OutputInterface $output): int
    {
        $type = $input->getArgument('type') ?? 'all';
        $filter = $input->getOption('filter');
        $coverage = $input->getOption('coverage');
        $parallel = $input->getOption('parallel');

        $output->writeln("<info>运行 {$type} 测试...</info>");

        return match ($type) {
            'unit' => $this->runUnitTests($output, $filter, $coverage),
            'integration' => $this->runIntegrationTests($output, $filter),
            'api' => $this->runApiTests($output, $filter),
            'e2e' => $this->runE2ETests($output, $filter),
            'performance' => $this->runPerformanceTests($output),
            'security' => $this->runSecurityTests($output),
            'all' => $this->runAllTests($output, $filter, $coverage, $parallel),
            default => $this->showError($output, "未知的测试类型: {$type}")
        };
    }

    private function runUnitTests($output, $filter, $coverage): int
    {
        $output->writeln("<info>运行单元测试...</info>");
        
        $command = "vendor/bin/phpunit tests/Unit --colors=always";
        
        if ($filter) {
            $command .= " --filter {$filter}";
        }
        
        if ($coverage) {
            $command .= " --coverage-html reports/coverage --coverage-clover reports/coverage.xml";
        }
        
        $this->executeCommand($output, $command);
        
        if ($coverage) {
            $output->writeln("<info>覆盖率报告已生成: reports/coverage/index.html</info>");
        }
        
        return 0;
    }

    private function runIntegrationTests($output, $filter): int
    {
        $output->writeln("<info>运行集成测试...</info>");
        
        // 启动测试环境
        $this->executeCommand($output, "docker-compose -f docker-compose.test.yml up -d");
        sleep(10); // 等待服务启动
        
        $command = "vendor/bin/phpunit tests/Integration --colors=always";
        
        if ($filter) {
            $command .= " --filter {$filter}";
        }
        
        $result = $this->executeCommand($output, $command);
        
        // 清理测试环境
        $this->executeCommand($output, "docker-compose -f docker-compose.test.yml down");
        
        return $result;
    }

    private function runApiTests($output, $filter): int
    {
        $output->writeln("<info>运行 API 测试...</info>");
        
        $command = "vendor/bin/codecept run api --colors";
        
        if ($filter) {
            $command .= " -g {$filter}";
        }
        
        return $this->executeCommand($output, $command);
    }

    private function runE2ETests($output, $filter): int
    {
        $output->writeln("<info>运行端到端测试...</info>");
        
        // 启动完整环境
        $this->executeCommand($output, "docker-compose up -d");
        $this->executeCommand($output, "kubectl apply -f k8s/");
        sleep(30); // 等待所有服务就绪
        
        $command = "vendor/bin/codecept run e2e --colors";
        
        if ($filter) {
            $command .= " -g {$filter}";
        }
        
        $result = $this->executeCommand($output, $command);
        
        // 清理环境
        $this->executeCommand($output, "kubectl delete -f k8s/");
        $this->executeCommand($output, "docker-compose down");
        
        return $result;
    }

    private function runPerformanceTests($output): int
    {
        $output->writeln("<info>运行性能测试...</info>");
        
        // 并发测试
        $this->executeCommand($output, "ab -n 10000 -c 100 http://localhost/api/users");
        
        // 内存测试
        $this->executeCommand($output, "php bin/console benchmark:memory");
        
        // 数据库性能测试
        $this->executeCommand($output, "php bin/console benchmark:database");
        
        return 0;
    }

    private function runSecurityTests($output): int
    {
        $output->writeln("<info>运行安全测试...</info>");
        
        // 依赖漏洞扫描
        $this->executeCommand($output, "composer audit");
        
        // 代码安全扫描
        $this->executeCommand($output, "vendor/bin/phpstan analyse --level=8");
        
        // API 安全测试
        $this->executeCommand($output, "vendor/bin/codecept run security");
        
        return 0;
    }

    private function runAllTests($output, $filter, $coverage, $parallel): int
    {
        $output->writeln("<info>运行所有测试...</info>");
        
        $tests = [
            'unit' => $this->runUnitTests($output, $filter, $coverage),
            'integration' => $this->runIntegrationTests($output, $filter),
            'api' => $this->runApiTests($output, $filter),
        ];
        
        $failed = array_filter($tests, fn($result) => $result !== 0);
        
        if (empty($failed)) {
            $output->writeln("<info>所有测试通过! ✅</info>");
            return 0;
        } else {
            $output->writeln("<error>部分测试失败! ❌</error>");
            return 1;
        }
    }

    private function executeCommand($output, string $command): int
    {
        $output->writeln("<comment>执行: {$command}</comment>");
        
        $process = proc_open($command, [
            1 => ['pipe', 'w'],
            2 => ['pipe', 'w'],
        ], $pipes);
        
        if (!is_resource($process)) {
            return 1;
        }
        
        // 读取输出
        while (($line = fgets($pipes[1])) !== false) {
            $output->write($line);
        }
        
        // 读取错误输出
        while (($line = fgets($pipes[2])) !== false) {
            $output->write("<error>{$line}</error>");
        }
        
        return proc_close($process);
    }

    private function showError($output, string $message): int
    {
        $output->writeln("<error>{$message}</error>");
        return 1;
    }
}

/**
 * 部署命令
 */
class DeployCommand extends \Fendx\Cli\Command\Command
{
    protected function configure(): void
    {
        $this->setName('deploy')
            ->setDescription('部署应用到指定环境')
            ->addArgument('environment', '部署环境: local, docker, k8s')
            ->addOption('force', 'f', '强制部署', false);
    }

    protected function execute(\Fendx\Cli\Input\InputInterface $input, \Fendx\Cli\Output\OutputInterface $output): int
    {
        $environment = $input->getArgument('environment');
        $force = $input->getOption('force');

        $output->writeln("<info>部署到 {$environment} 环境...</info>");

        return match ($environment) {
            'local' => $this->deployLocal($output, $force),
            'docker' => $this->deployDocker($output, $force),
            'k8s' => $this->deployKubernetes($output, $force),
            default => $this->showError($output, "未知的环境: {$environment}")
        };
    }

    private function deployLocal($output, $force): int
    {
        $output->writeln("<info>部署到本地环境...</info>");
        
        // 检查依赖
        $this->executeCommand($output, "composer install");
        
        // 运行迁移
        $this->executeCommand($output, "php bin/console migrate:run");
        
        // 设置权限
        $this->executeCommand($output, "chmod -R 755 storage/ runtime/");
        
        $output->writeln("<info>本地部署完成! 🎉</info>");
        return 0;
    }

    private function deployDocker($output, $force): int
    {
        $output->writeln("<info>部署到 Docker 环境...</info>");
        
        if ($force) {
            $this->executeCommand($output, "docker-compose down --volumes");
        }
        
        $this->executeCommand($output, "docker-compose up -d --build");
        
        // 等待服务启动
        $output->writeln("<comment>等待服务启动...</comment>");
        sleep(30);
        
        // 健康检查
        $this->executeCommand($output, "curl -f http://localhost/health");
        
        $output->writeln("<info>Docker 部署完成! 🐳</info>");
        return 0;
    }

    private function deployKubernetes($output, $force): int
    {
        $output->writeln("<info>部署到 Kubernetes 环境...</info>");
        
        if ($force) {
            $this->executeCommand($output, "kubectl delete namespace fendx");
        }
        
        $this->executeCommand($output, "kubectl apply -f k8s/");
        
        // 等待部署完成
        $this->executeCommand($output, "kubectl rollout status deployment/fendx-php -n fendx");
        
        $output->writeln("<info>Kubernetes 部署完成! ☸️</info>");
        return 0;
    }
}

/**
 * 基准测试命令
 */
class BenchmarkCommand extends \Fendx\Cli\Command\Command
{
    protected function configure(): void
    {
        $this->setName('benchmark')
            ->setDescription('运行性能基准测试')
            ->addArgument('type', '测试类型: all, memory, database, cache, api');
    }

    protected function execute(\Fendx\Cli\Input\InputInterface $input, \Fendx\Cli\Output\OutputInterface $output): int
    {
        $type = $input->getArgument('type') ?? 'all';
        
        $output->writeln("<info>运行 {$type} 基准测试...</info>");
        
        return match ($type) {
            'memory' => $this->benchmarkMemory($output),
            'database' => $this->benchmarkDatabase($output),
            'cache' => $this->benchmarkCache($output),
            'api' => $this->benchmarkApi($output),
            'all' => $this->benchmarkAll($output),
            default => $this->showError($output, "未知的测试类型: {$type}")
        };
    }

    private function benchmarkMemory($output): int
    {
        $output->writeln("<info>内存基准测试...</info>");
        
        $start = memory_get_usage();
        
        // 模拟业务逻辑
        for ($i = 0; $i < 100000; $i++) {
            $data = ['id' => $i, 'name' => "user_{$i}", 'email' => "user{$i}@example.com"];
            $json = json_encode($data);
            $array = json_decode($json, true);
        }
        
        $end = memory_get_usage();
        $used = ($end - $start) / 1024 / 1024;
        
        $output->writeln("<info>内存使用: {$used} MB</info>");
        return 0;
    }

    private function benchmarkDatabase($output): int
    {
        $output->writeln("<info>数据库基准测试...</info>");
        
        $start = microtime(true);
        
        // 模拟数据库查询
        for ($i = 0; $i < 1000; $i++) {
            // 这里应该执行实际的数据库查询
            usleep(100); // 模拟 0.1ms 查询时间
        }
        
        $end = microtime(true);
        $duration = ($end - $start) * 1000;
        
        $output->writeln("<info>1000 次查询耗时: {$duration} ms</info>");
        return 0;
    }

    private function benchmarkCache($output): int
    {
        $output->writeln("<info>缓存基准测试...</info>");
        
        $start = microtime(true);
        
        // 模拟缓存操作
        for ($i = 0; $i < 10000; $i++) {
            // 模拟缓存写入
            usleep(10); // 模拟 0.01ms 缓存时间
            // 模拟缓存读取
            usleep(5); // 模拟 0.005ms 缓存时间
        }
        
        $end = microtime(true);
        $duration = ($end - $start) * 1000;
        
        $output->writeln("<info>20000 次缓存操作耗时: {$duration} ms</info>");
        return 0;
    }

    private function benchmarkApi($output): int
    {
        $output->writeln("<info>API 基准测试...</info>");
        
        $this->executeCommand($output, "ab -n 1000 -c 10 http://localhost/api/users");
        
        return 0;
    }

    private function benchmarkAll($output): int
    {
        $this->benchmarkMemory($output);
        $this->benchmarkDatabase($output);
        $this->benchmarkCache($output);
        $this->benchmarkApi($output);
        
        return 0;
    }
}

// 运行控制台应用
try {
    $app = new ConsoleApplication();
    $app->run();
} catch (\Exception $e) {
    echo "Error: " . $e->getMessage() . "\n";
    exit(1);
}
