<?php

namespace Kylin\Modules\Console\Commands;

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

/**
 * 模块配置管理命令
 *
 * 管理模块的配置文件，帮助开发者更好地处理模块的配置
 */
class ModuleConfigCommand extends Command
{
    /**
     * 命令名称和签名
     *
     * @var string
     * 
     * 命令参数说明：
     * 1. {module} - 模块名称（必填）
     *    - 数据类型：字符串
     *    - 用途：指定要管理配置的模块名称
     *    - 示例：php artisan module:config game
     * 
     * 命令选项说明：
     * 1. {--list} - 列出模块的所有配置文件
     *    - 完整形式：--list
     *    - 用途：列出模块的所有配置文件
     *    - 示例：php artisan module:config game --list
     * 
     * 2. {--make=} - 创建新的配置文件
     *    - 完整形式：--make
     *    - 数据类型：字符串
     *    - 用途：创建新的配置文件（如：config）
     *    - 示例：php artisan module:config game --make=config
     * 
     * 3. {--get=} - 获取配置项的值
     *    - 完整形式：--get
     *    - 数据类型：字符串
     *    - 用途：获取配置项的值（如：config.key）
     *    - 示例：php artisan module:config game --get=config.key
     * 
     * 4. {--set=} - 设置配置项的值
     *    - 完整形式：--set
     *    - 数据类型：字符串
     *    - 用途：设置配置项的值（如：config.key=value）
     *    - 示例：php artisan module:config game --set=config.key=value
     * 
     * 5. {--publish} - 发布模块的配置文件
     *    - 完整形式：--publish
     *    - 用途：发布模块的配置文件到应用配置目录
     *    - 示例：php artisan module:config game --publish
     * 
     * 6. {--cache} - 缓存模块的配置
     *    - 完整形式：--cache
     *    - 用途：缓存模块的配置，提高加载速度
     *    - 示例：php artisan module:config game --cache
     * 
     * 7. {--clear} - 清除模块的配置缓存
     *    - 完整形式：--clear
     *    - 用途：清除模块的配置缓存，确保配置变更能够生效
     *    - 示例：php artisan module:config game --clear
     */
    protected $signature = 'module:config {module : 模块名称} {--list : 列出模块的所有配置文件} {--make= : 创建新的配置文件（如：config）} {--get= : 获取配置项的值（如：config.key）} {--set= : 设置配置项的值（如：config.key=value）} {--publish : 发布模块的配置文件} {--cache : 缓存模块的配置} {--clear : 清除模块的配置缓存}';

    /**
     * 命令描述
     *
     * @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');
        $list = $this->option('list');
        $make = $this->option('make');
        $get = $this->option('get');
        $set = $this->option('set');
        $publish = $this->option('publish');
        $cache = $this->option('cache');
        $clear = $this->option('clear');

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

        $modulePath = $module->getPath();
        $configPath = "{$modulePath}/config";

        // 确保配置目录存在
        if (!($this->files->exists($configPath))) {
            $this->files->makeDirectory($configPath, 0755, true);
            $this->info("创建配置目录: {$configPath}");
        }

        // 列出模块的所有配置文件
        if ($list) {
            return $this->listConfigFiles($moduleName, $configPath);
        }

        // 创建新的配置文件
        if ($make) {
            return $this->makeConfigFile($configPath, (string) $make);
        }

        // 获取配置项的值
        if ($get) {
            return $this->getConfigValue($moduleName, (string) $get);
        }

        // 设置配置项的值
        if ($set) {
            return $this->setConfigValue($configPath, (string) $set);
        }

        // 发布模块的配置文件
        if ($publish) {
            return $this->publishConfigFiles($moduleName);
        }

        // 缓存模块的配置
        if ($cache) {
            return $this->cacheConfig($moduleName);
        }

        // 清除模块的配置缓存
        if ($clear) {
            return $this->clearConfigCache($moduleName);
        }

        // 默认列出模块的所有配置文件
        return $this->listConfigFiles($moduleName, $configPath);
    }

    /**
     * 列出模块的所有配置文件
     *
     * @param  string  $moduleName  模块名称
     * @param  string  $configPath  配置文件目录路径
     * @return int  退出码
     */
    protected function listConfigFiles(string $moduleName, string $configPath): int
    {
        $this->info("模块 [{$moduleName}] 的配置文件:");

        $configFiles = $this->files->files($configPath);

        if (empty($configFiles)) {
            $this->info('  没有找到配置文件');
            return 0;
        }

        foreach ($configFiles as $file) {
            $fileName = $file->getFilename();
            $this->line("  - {$fileName}");
        }

        return 0;
    }

    /**
     * 创建新的配置文件
     *
     * @param  string  $configPath  配置文件目录路径
     * @param  string  $name  配置文件名称
     * @return int  退出码
     */
    protected function makeConfigFile(string $configPath, string $name): int
    {
        $configFile = "{$configPath}/{$name}.php";

        if ($this->files->exists($configFile)) {
            $this->error("配置文件 [{$name}.php] 已存在");
            return 1;
        }

        $content = "<?php\n\nreturn [\n    //\n];\n";

        $this->files->put($configFile, $content);
        $this->info("创建配置文件: {$configFile}");

        return 0;
    }

    /**
     * 获取配置项的值
     *
     * @param  string  $moduleName  模块名称
     * @param  string  $key  配置项键
     * @return int  退出码
     */
    protected function getConfigValue(string $moduleName, string $key): int
    {
        $parts = explode('.', $key);
        $configFile = array_shift($parts);
        $configKey = implode('.', $parts);

        $config = config("{$moduleName}.{$configFile}");

        if (is_null($config)) {
            $this->error("配置文件 [{$configFile}] 不存在");
            return 1;
        }

        if (!empty($configKey)) {
            $value = data_get($config, $configKey);
        } else {
            $value = $config;
        }

        $this->info("配置项 [{$key}] 的值:");
        $this->line(print_r($value, true));

        return 0;
    }

    /**
     * 设置配置项的值
     *
     * @param  string  $configPath  配置文件目录路径
     * @param  string  $keyValue  配置项键值对
     * @return int  退出码
     */
    protected function setConfigValue(string $configPath, string $keyValue): int
    {
        $parts = explode('=', $keyValue, 2);
        if (count($parts) !== 2) {
            $this->error('设置格式错误，请使用：--set=config.key=value');
            return 1;
        }

        [$key, $value] = $parts;
        $keyParts = explode('.', $key);
        $configFile = array_shift($keyParts);
        $configKey = implode('.', $keyParts);

        $configFilepath = "{$configPath}/{$configFile}.php";

        if (!($this->files->exists($configFilepath))) {
            $this->error("配置文件 [{$configFile}.php] 不存在");
            return 1;
        }

        $config = require $configFilepath;
        data_set($config, $configKey, $value);

        $content = "<?php\n\nreturn " . var_export($config, true) . ";\n";
        $this->files->put($configFilepath, $content);

        $this->info("设置配置项 [{$key}] 的值为: {$value}");

        return 0;
    }

    /**
     * 发布模块的配置文件
     *
     * @param  string  $moduleName  模块名称
     * @return int  退出码
     */
    protected function publishConfigFiles(string $moduleName): int
    {
        $this->info("发布模块 [{$moduleName}] 的配置文件...");

        // 运行全局配置发布命令
        $this->call('vendor:publish', [
            '--provider' => "{$moduleName}\Providers\{$moduleName}ServiceProvider",
            '--tag' => 'config',
        ]);

        $this->info("模块 [{$moduleName}] 的配置文件发布完成");

        return 0;
    }

    /**
     * 缓存模块的配置
     *
     * @param  string  $moduleName  模块名称
     * @return int  退出码
     */
    protected function cacheConfig(string $moduleName): int
    {
        $this->info("缓存模块 [{$moduleName}] 的配置...");

        // 运行全局配置缓存命令
        $this->call('config:cache');

        $this->info("模块 [{$moduleName}] 的配置缓存完成");

        return 0;
    }

    /**
     * 清除模块的配置缓存
     *
     * @param  string  $moduleName  模块名称
     * @return int  退出码
     */
    protected function clearConfigCache(string $moduleName): int
    {
        $this->info("清除模块 [{$moduleName}] 的配置缓存...");

        // 运行全局配置缓存清除命令
        $this->call('config:clear');

        $this->info("模块 [{$moduleName}] 的配置缓存清除完成");

        return 0;
    }
}
