<?php

namespace Kylin\Modules\Console\Commands;

use Illuminate\Console\Command;
use Illuminate\Filesystem\Filesystem;
use Kylin\Modules\ModuleManager;

/**
 * 模块监控命令
 *
 * 监控模块的运行状态、性能指标等
 */
class ModuleMonitorCommand extends Command
{
    /**
     * 命令名称和签名
     *
     * @var string
     * 
     * 命令参数说明：
     * 1. {modules?*} - 模块名称列表（可选）
     *    - 数据类型：字符串数组
     *    - 用途：指定要监控的模块名称列表，不指定则监控所有模块
     *    - 示例：php artisan module:monitor game user
     * 
     * 命令选项说明：
     * 1. {--all} - 监控所有模块
     *    - 完整形式：--all
     *    - 用途：监控所有模块
     *    - 示例：php artisan module:monitor --all
     * 
     * 2. {--interval=5} - 监控间隔
     *    - 完整形式：--interval
     *    - 数据类型：整数
     *    - 用途：指定监控间隔（秒）
     *    - 默认值：5
     *    - 示例：php artisan module:monitor game --interval=10
     * 
     * 3. {--duration=300} - 监控持续时间
     *    - 完整形式：--duration
     *    - 数据类型：整数
     *    - 用途：指定监控持续时间（秒）
     *    - 默认值：300
     *    - 示例：php artisan module:monitor game --duration=600
     * 
     * 4. {--metrics=*} - 监控指标
     *    - 完整形式：--metrics
     *    - 数据类型：字符串数组
     *    - 用途：指定要监控的指标（memory, time, files, routes）
     *    - 示例：php artisan module:monitor game --metrics=memory,time
     * 
     * 5. {--output=console} - 输出方式
     *    - 完整形式：--output
     *    - 数据类型：字符串
     *    - 用途：指定输出方式（console, file, json）
     *    - 默认值：console
     *    - 示例：php artisan module:monitor game --output=file
     * 
     * 6. {--file=} - 输出文件路径
     *    - 完整形式：--file
     *    - 数据类型：字符串
     *    - 用途：指定输出文件路径（当 output=file 或 json 时使用）
     *    - 示例：php artisan module:monitor game --output=file --file=monitor.log
     */
    protected $signature = 'module:monitor {modules?* : 模块名称列表} {--all : 监控所有模块} {--interval=5 : 监控间隔（秒）} {--duration=300 : 监控持续时间（秒）} {--metrics=* : 监控指标（memory, time, files, routes）} {--output=console : 输出方式（console, file, json）} {--file= : 输出文件路径（当 output=file 或 json 时使用）}';

    /**
     * 命令描述
     *
     * @var string
     */
    protected $description = '监控模块的运行状态、性能指标等';

    /**
     * 文件系统实例
     *
     * @var Filesystem
     */
    private readonly Filesystem $files;

    /**
     * 创建新命令实例
     *
     * @param  ModuleManager  $moduleManager  模块管理器实例
     * @param  Filesystem  $files  文件系统实例
     */
    public function __construct(
        private readonly ModuleManager $moduleManager,
        Filesystem $files
    ) {
        parent::__construct();
        $this->files = $files;
    }

    /**
     * 执行控制台命令
     */
    public function handle(): int
    {
        $modules = $this->argument('modules') ?: [];
        $all = $this->option('all');
        $interval = (int) ($this->option('interval') ?: 5);
        $duration = (int) ($this->option('duration') ?: 300);
        $metrics = $this->option('metrics') ?: ['memory', 'time', 'files'];
        $output = $this->option('output') ?: 'console';
        $file = $this->option('file');

        // 确定要监控的模块
        $targetModules = [];
        if ($all) {
            $targetModules = $this->moduleManager->all();
        } elseif (!empty($modules)) {
            foreach ($modules as $moduleName) {
                $module = $this->moduleManager->get($moduleName);
                if ($module) {
                    $targetModules[] = $module;
                } else {
                    $this->warn("模块 [{$moduleName}] 未找到，将被跳过。");
                }
            }
        } else {
            $this->error('请指定模块名称或使用 --all 选项');
            return 1;
        }

        if (empty($targetModules)) {
            $this->error('没有找到要监控的模块');
            return 1;
        }

        // 确定输出文件路径
        if ($output !== 'console' && !$file) {
            $file = storage_path('logs/module-monitor-' . date('YmdHis') . '.' . ($output === 'json' ? 'json' : 'log'));
        }

        $this->info("开始监控模块...");
        $this->line("监控间隔: {$interval} 秒");
        $this->line("监控持续时间: {$duration} 秒");
        $this->line("监控指标: " . implode(', ', $metrics));
        $this->line("输出方式: {$output}");
        if ($file) {
            $this->line("输出文件: {$file}");
        }
        $this->line('');

        // 开始监控
        $startTime = time();
        $endTime = $startTime + $duration;
        $monitorData = [];

        while (time() < $endTime) {
            $timestamp = date('Y-m-d H:i:s');
            $this->line("[{$timestamp}] 收集监控数据...");

            foreach ($targetModules as $module) {
                $moduleName = $module->getName();
                $moduleData = [
                    'timestamp' => $timestamp,
                    'module' => $moduleName,
                    'metrics' => [],
                ];

                // 收集内存使用情况
                if (in_array('memory', $metrics)) {
                    $moduleData['metrics']['memory'] = $this->getMemoryUsage();
                }

                // 收集执行时间
                if (in_array('time', $metrics)) {
                    $moduleData['metrics']['time'] = $this->getTimeMetrics($module);
                }

                // 收集文件信息
                if (in_array('files', $metrics)) {
                    $moduleData['metrics']['files'] = $this->getFileMetrics($module);
                }

                // 收集路由信息
                if (in_array('routes', $metrics)) {
                    $moduleData['metrics']['routes'] = $this->getRouteMetrics($module);
                }

                $monitorData[] = $moduleData;

                // 显示监控数据
                if ($output === 'console') {
                    $this->line("  模块 [{$moduleName}]:");
                    foreach ($moduleData['metrics'] as $metricName => $metricValue) {
                        if (is_array($metricValue)) {
                            $this->line("    {$metricName}:");
                            foreach ($metricValue as $key => $value) {
                                $this->line("      {$key}: {$value}");
                            }
                        } else {
                            $this->line("    {$metricName}: {$metricValue}");
                        }
                    }
                }
            }

            $this->line('');

            // 等待指定间隔
            sleep($interval);
        }

        $this->info("监控完成");

        // 处理输出
        if ($output === 'file') {
            $this->saveToFile($file, $monitorData);
        } elseif ($output === 'json') {
            $this->saveToJson($file, $monitorData);
        }

        return 0;
    }

    /**
     * 获取内存使用情况
     *
     * @return array  内存使用情况
     */
    protected function getMemoryUsage(): array
    {
        return [
            'current' => memory_get_usage(true),
            'peak' => memory_get_peak_usage(true),
            'limit' => ini_get('memory_limit'),
        ];
    }

    /**
     * 获取时间指标
     *
     * @param  mixed  $module  模块实例
     * @return array  时间指标
     */
    protected function getTimeMetrics($module): array
    {
        $start = microtime(true);

        // 模拟模块操作以测量时间
        $module->getPath();

        $end = microtime(true);

        return [
            'execution' => ($end - $start) * 1000, // 毫秒
        ];
    }

    /**
     * 获取文件指标
     *
     * @param  mixed  $module  模块实例
     * @return array  文件指标
     */
    protected function getFileMetrics($module): array
    {
        $modulePath = $module->getPath();
        $fileCount = 0;
        $dirCount = 0;

        // 遍历模块目录
        if ($this->files->exists($modulePath)) {
            // 统计文件数量
            $files = $this->files->allFiles($modulePath);
            $fileCount = count($files);
            
            // 统计目录数量
            $directories = $this->files->directories($modulePath);
            $dirCount = count($directories);
            
            // 递归统计子目录
            foreach ($directories as $directory) {
                $subDirs = $this->files->directories($directory);
                $dirCount += count($subDirs);
            }
        }

        return [
            'files' => $fileCount,
            'directories' => $dirCount,
        ];
    }

    /**
     * 获取路由指标
     *
     * @param  mixed  $module  模块实例
     * @return array  路由指标
     */
    protected function getRouteMetrics($module): array
    {
        $modulePath = $module->getPath();
        $routesPath = "{$modulePath}/routes/web.php";
        $routeCount = 0;

        if ($this->files->exists($routesPath)) {
            $routesContent = $this->files->get($routesPath);
            // 简单计算路由数量
            $routeCount = substr_count($routesContent, 'Route::');
        }

        return [
            'count' => $routeCount,
        ];
    }

    /**
     * 保存监控数据到文件
     *
     * @param  string  $file  文件路径
     * @param  array  $data  监控数据
     */
    protected function saveToFile(string $file, array $data): void
    {
        $content = "模块监控数据 - " . date('Y-m-d H:i:s') . "\n\n";

        foreach ($data as $item) {
            $content .= "时间: {$item['timestamp']}\n";
            $content .= "模块: {$item['module']}\n";
            $content .= "指标:\n";

            foreach ($item['metrics'] as $metricName => $metricValue) {
                if (is_array($metricValue)) {
                    $content .= "  {$metricName}:\n";
                    foreach ($metricValue as $key => $value) {
                        $content .= "    {$key}: {$value}\n";
                    }
                } else {
                    $content .= "  {$metricName}: {$metricValue}\n";
                }
            }

            $content .= "\n";
        }

        $this->files->put($file, $content);
        $this->info("监控数据已保存到: {$file}");
    }

    /**
     * 保存监控数据到 JSON 文件
     *
     * @param  string  $file  文件路径
     * @param  array  $data  监控数据
     */
    protected function saveToJson(string $file, array $data): void
    {
        $jsonData = json_encode($data, JSON_PRETTY_PRINT);
        $this->files->put($file, $jsonData);
        $this->info("监控数据已保存到: {$file}");
    }
}
