<?php

namespace Kylin\Modules\Console\Commands;

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

/**
 * 模块依赖管理命令
 *
 * 管理模块之间的依赖关系
 */
class ModuleDependencyCommand extends Command
{
    /**
     * 命令名称和签名
     *
     * @var string
     * 
     * 命令参数说明：
     * 1. {module} - 模块名称（必填）
     *    - 数据类型：字符串
     *    - 用途：指定要管理依赖的模块名称
     *    - 示例：php artisan module:dependency game
     * 
     * 命令选项说明：
     * 1. {--add=} - 添加依赖模块
     *    - 完整形式：--add
     *    - 数据类型：字符串
     *    - 用途：添加依赖模块
     *    - 示例：php artisan module:dependency game --add=user
     * 
     * 2. {--remove=} - 移除依赖模块
     *    - 完整形式：--remove
     *    - 数据类型：字符串
     *    - 用途：移除依赖模块
     *    - 示例：php artisan module:dependency game --remove=user
     * 
     * 3. {--list} - 列出所有依赖
     *    - 完整形式：--list
     *    - 用途：列出模块的所有依赖
     *    - 示例：php artisan module:dependency game --list
     * 
     * 4. {--check} - 检查依赖关系
     *    - 完整形式：--check
     *    - 用途：检查模块的依赖关系是否正确
     *    - 示例：php artisan module:dependency game --check
     */
    protected $signature = 'module:dependency {module : 模块名称} {--add= : 添加依赖模块} {--remove= : 移除依赖模块} {--list : 列出所有依赖} {--check : 检查依赖关系}';

    /**
     * 命令描述
     *
     * @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
    {
        $moduleName = (string) $this->argument('module');
        $addDependency = $this->option('add');
        $removeDependency = $this->option('remove');
        $listDependencies = $this->option('list');
        $checkDependencies = $this->option('check');

        // 检查模块是否存在
        $module = $this->moduleManager->get($moduleName);
        if (!$module) {
            $this->error("模块 [{$moduleName}] 未找到。");
            return 1;
        }

        // 获取模块的 composer.json 文件路径
        $composerPath = $module->getPath() . '/composer.json';
        if (!$this->files->exists($composerPath)) {
            $this->error("模块 [{$moduleName}] 缺少 composer.json 文件。");
            return 1;
        }

        // 读取 composer.json 文件
        $composerContent = json_decode($this->files->get($composerPath), true);
        if (json_last_error() !== JSON_ERROR_NONE) {
            $this->error("模块 [{$moduleName}] 的 composer.json 文件格式错误。");
            return 1;
        }

        // 确保 require 部分存在
        if (!isset($composerContent['require'])) {
            $composerContent['require'] = [];
        }

        // 处理添加依赖
        if ($addDependency) {
            return $this->addDependency($moduleName, $composerPath, $composerContent, (string) $addDependency);
        }

        // 处理移除依赖
        if ($removeDependency) {
            return $this->removeDependency($moduleName, $composerPath, $composerContent, (string) $removeDependency);
        }

        // 处理列出依赖
        if ($listDependencies) {
            return $this->listDependencies($moduleName, $composerContent);
        }

        // 处理检查依赖
        if ($checkDependencies) {
            return $this->checkDependencies($moduleName, $composerContent);
        }

        // 默认列出依赖
        return $this->listDependencies($moduleName, $composerContent);
    }

    /**
     * 添加依赖
     *
     * @param  string  $moduleName  模块名称
     * @param  string  $composerPath  composer.json 文件路径
     * @param  array  $composerContent  composer.json 内容
     * @param  string  $dependency  依赖模块名称
     * @return int  退出码
     */
    protected function addDependency(string $moduleName, string $composerPath, array $composerContent, string $dependency): int
    {
        // 检查依赖模块是否存在
        $dependencyModule = $this->moduleManager->get($dependency);
        if (!$dependencyModule) {
            $this->error("依赖模块 [{$dependency}] 未找到。");
            return 1;
        }

        // 构建依赖包名
        $dependencyPackage = $this->getModulePackageName($dependencyModule);
        if (!$dependencyPackage) {
            $this->error("无法确定依赖模块 [{$dependency}] 的包名。");
            return 1;
        }

        // 添加依赖
        $composerContent['require'][$dependencyPackage] = '*';

        // 保存 composer.json 文件
        $this->files->put($composerPath, json_encode($composerContent, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));

        $this->info("已成功添加依赖: {$dependencyPackage} 到模块 [{$moduleName}]。");
        $this->info("提示：请运行 composer update 来更新依赖。");

        return 0;
    }

    /**
     * 移除依赖
     *
     * @param  string  $moduleName  模块名称
     * @param  string  $composerPath  composer.json 文件路径
     * @param  array  $composerContent  composer.json 内容
     * @param  string  $dependency  依赖模块名称
     * @return int  退出码
     */
    protected function removeDependency(string $moduleName, string $composerPath, array $composerContent, string $dependency): int
    {
        // 检查依赖模块是否存在
        $dependencyModule = $this->moduleManager->get($dependency);
        if (!$dependencyModule) {
            $this->error("依赖模块 [{$dependency}] 未找到。");
            return 1;
        }

        // 构建依赖包名
        $dependencyPackage = $this->getModulePackageName($dependencyModule);
        if (!$dependencyPackage) {
            $this->error("无法确定依赖模块 [{$dependency}] 的包名。");
            return 1;
        }

        // 检查依赖是否存在
        if (!isset($composerContent['require'][$dependencyPackage])) {
            $this->error("模块 [{$moduleName}] 不依赖于 [{$dependency}]。");
            return 1;
        }

        // 移除依赖
        unset($composerContent['require'][$dependencyPackage]);

        // 保存 composer.json 文件
        $this->files->put($composerPath, json_encode($composerContent, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));

        $this->info("已成功移除依赖: {$dependencyPackage} 从模块 [{$moduleName}]。");
        $this->info("提示：请运行 composer update 来更新依赖。");

        return 0;
    }

    /**
     * 列出依赖
     *
     * @param  string  $moduleName  模块名称
     * @param  array  $composerContent  composer.json 内容
     * @return int  退出码
     */
    protected function listDependencies(string $moduleName, array $composerContent): int
    {
        $this->info("模块 [{$moduleName}] 的依赖关系：");
        $this->line('');

        if (empty($composerContent['require'])) {
            $this->info("无依赖。");
            return 0;
        }

        $headers = ['依赖包', '版本约束'];
        $rows = [];

        foreach ($composerContent['require'] as $package => $version) {
            $rows[] = [$package, $version];
        }

        $this->table($headers, $rows);

        return 0;
    }

    /**
     * 检查依赖
     *
     * @param  string  $moduleName  模块名称
     * @param  array  $composerContent  composer.json 内容
     * @return int  退出码
     */
    protected function checkDependencies(string $moduleName, array $composerContent): int
    {
        $this->info("检查模块 [{$moduleName}] 的依赖关系：");
        $this->line('');

        if (empty($composerContent['require'])) {
            $this->info("无依赖需要检查。");
            return 0;
        }

        $missingDependencies = [];
        $foundDependencies = [];

        foreach ($composerContent['require'] as $package => $version) {
            // 检查依赖是否已安装
            $dependencyInstalled = $this->isDependencyInstalled($package);
            if ($dependencyInstalled) {
                $foundDependencies[] = [$package, $version, '已安装'];
            } else {
                $missingDependencies[] = [$package, $version, '未安装'];
            }
        }

        // 显示已安装的依赖
        if (!empty($foundDependencies)) {
            $this->info('已安装的依赖：');
            $this->table(['依赖包', '版本约束', '状态'], $foundDependencies);
            $this->line('');
        }

        // 显示未安装的依赖
        if (!empty($missingDependencies)) {
            $this->info('未安装的依赖：');
            $this->table(['依赖包', '版本约束', '状态'], $missingDependencies);
            $this->line('');
            $this->error("发现 {$missingDependencies} 个未安装的依赖。");
            $this->info("提示：请运行 composer install 来安装依赖。");
            return 1;
        }

        $this->info('所有依赖都已安装。');
        return 0;
    }

    /**
     * 获取模块的包名
     *
     * @param  mixed  $module  模块实例
     * @return string|null  包名
     */
    protected function getModulePackageName($module): ?string
    {
        $composerPath = $module->getPath() . '/composer.json';
        if (!$this->files->exists($composerPath)) {
            return null;
        }

        $composerContent = json_decode($this->files->get($composerPath), true);
        if (json_last_error() !== JSON_ERROR_NONE) {
            return null;
        }

        return $composerContent['name'] ?? null;
    }

    /**
     * 检查依赖是否已安装
     *
     * @param  string  $package  包名
     * @return bool  是否已安装
     */
    protected function isDependencyInstalled(string $package): bool
    {
        // 检查 vendor 目录中是否存在该包
        $vendorPath = base_path('vendor') . '/' . str_replace('\\', '/', $package);
        return $this->files->exists($vendorPath);
    }
}
