<?php

namespace Kylin\Modules\Console\Commands;

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

/**
 * 模块国际化命令
 *
 * 管理模块的国际化资源，帮助开发者更好地处理模块的多语言支持
 */
class ModuleI18nCommand extends Command
{
    /**
     * 命令名称和签名
     *
     * @var string
     * 
     * 命令参数说明：
     * 1. {module} - 模块名称（必填）
     *    - 数据类型：字符串
     *    - 用途：指定要管理国际化资源的模块名称
     *    - 示例：php artisan module:i18n game
     * 
     * 命令选项说明：
     * 1. {--list} - 列出所有语言文件
     *    - 完整形式：--list
     *    - 用途：列出模块的所有语言文件
     *    - 示例：php artisan module:i18n game --list
     * 
     * 2. {--add=} - 添加新的语言文件
     *    - 完整形式：--add
     *    - 数据类型：字符串
     *    - 用途：添加新的语言文件（如：en, zh-CN）
     *    - 示例：php artisan module:i18n game --add=zh-CN
     * 
     * 3. {--copy=} - 从现有语言文件复制
     *    - 完整形式：--copy
     *    - 数据类型：字符串
     *    - 用途：从现有语言文件复制（如：从 en 复制到 fr）
     *    - 示例：php artisan module:i18n game --copy=en:fr
     * 
     * 4. {--sync=} - 同步语言文件
     *    - 完整形式：--sync
     *    - 数据类型：字符串
     *    - 用途：同步语言文件（如：同步 en 到所有其他语言）
     *    - 示例：php artisan module:i18n game --sync=en
     * 
     * 5. {--missing} - 检查缺失的翻译
     *    - 完整形式：--missing
     *    - 用途：检查模块中缺失的翻译
     *    - 示例：php artisan module:i18n game --missing
     * 
     * 6. {--export=} - 导出语言文件为 CSV 格式
     *    - 完整形式：--export
     *    - 数据类型：字符串
     *    - 用途：导出语言文件为 CSV 格式
     *    - 示例：php artisan module:i18n game --export=translations.csv
     * 
     * 7. {--import=} - 从 CSV 文件导入翻译
     *    - 完整形式：--import
     *    - 数据类型：字符串
     *    - 用途：从 CSV 文件导入翻译
     *    - 示例：php artisan module:i18n game --import=translations.csv
     */
    protected $signature = 'module:i18n {module : 模块名称} {--list : 列出所有语言文件} {--add= : 添加新的语言文件（如：en, zh-CN）} {--copy= : 从现有语言文件复制（如：从 en 复制到 fr）} {--sync= : 同步语言文件（如：同步 en 到所有其他语言）} {--missing : 检查缺失的翻译} {--export= : 导出语言文件为 CSV 格式} {--import= : 从 CSV 文件导入翻译}';

    /**
     * 命令描述
     *
     * @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');
        $add = $this->option('add');
        $copy = $this->option('copy');
        $sync = $this->option('sync');
        $missing = $this->option('missing');
        $export = $this->option('export');
        $import = $this->option('import');

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

        $modulePath = $module->getPath();
        $langPath = "{$modulePath}/resources/lang";

        // 检查语言目录是否存在
        if (!$this->files->exists($langPath)) {
            $this->files->makeDirectory($langPath, 0755, true);
            $this->info("创建语言目录: {$langPath}");
        }

        // 列出所有语言文件
        if ($list) {
            return $this->listLanguageFiles($langPath);
        }

        // 添加新的语言文件
        if ($add) {
            return $this->addLanguageFile($langPath, (string) $add);
        }

        // 从现有语言文件复制
        if ($copy) {
            $parts = explode(':', (string) $copy);
            if (count($parts) !== 2) {
                $this->error('复制格式错误，请使用：--copy=from:to');
                return 1;
            }
            return $this->copyLanguageFile($langPath, $parts[0], $parts[1]);
        }

        // 同步语言文件
        if ($sync) {
            return $this->syncLanguageFiles($langPath, (string) $sync);
        }

        // 检查缺失的翻译
        if ($missing) {
            return $this->checkMissingTranslations($langPath);
        }

        // 导出语言文件为 CSV 格式
        if ($export) {
            return $this->exportLanguageFiles($langPath, (string) $export);
        }

        // 从 CSV 文件导入翻译
        if ($import) {
            return $this->importLanguageFiles($langPath, (string) $import);
        }

        // 默认列出所有语言文件
        return $this->listLanguageFiles($langPath);
    }

    /**
     * 列出所有语言文件
     *
     * @param  string  $langPath  语言文件路径
     * @return int  退出码
     */
    protected function listLanguageFiles(string $langPath): int
    {
        $languages = $this->files->directories($langPath);

        if (empty($languages)) {
            $this->info('没有找到语言文件');
            return 0;
        }

        $this->info('可用的语言文件:');

        foreach ($languages as $language) {
            $langCode = basename($language);
            $files = $this->files->files($language);
            $fileCount = count($files);

            $this->line("  {$langCode} ({$fileCount} 个文件)");

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

        return 0;
    }

    /**
     * 添加新的语言文件
     *
     * @param  string  $langPath  语言文件路径
     * @param  string  $langCode  语言代码
     * @return int  退出码
     */
    protected function addLanguageFile(string $langPath, string $langCode): int
    {
        $newLangPath = "{$langPath}/{$langCode}";

        if ($this->files->exists($newLangPath)) {
            $this->error("语言 [{$langCode}] 已存在");
            return 1;
        }

        $this->files->makeDirectory($newLangPath, 0755, true);

        // 创建默认的语言文件
        $this->files->put(
            "{$newLangPath}/messages.php",
            "<?php\n\nreturn [\n    //\n];\n"
        );

        $this->info("添加语言 [{$langCode}] 成功");

        return 0;
    }

    /**
     * 从现有语言文件复制
     *
     * @param  string  $langPath  语言文件路径
     * @param  string  $fromLang  源语言
     * @param  string  $toLang  目标语言
     * @return int  退出码
     */
    protected function copyLanguageFile(string $langPath, string $fromLang, string $toLang): int
    {
        $fromPath = "{$langPath}/{$fromLang}";
        $toPath = "{$langPath}/{$toLang}";

        if (!($this->files->exists($fromPath))) {
            $this->error("源语言 [{$fromLang}] 不存在");
            return 1;
        }

        if ($this->files->exists($toPath)) {
            $this->error("目标语言 [{$toLang}] 已存在");
            return 1;
        }

        $this->files->makeDirectory($toPath, 0755, true);

        // 复制所有语言文件
        $files = $this->files->files($fromPath);

        foreach ($files as $file) {
            $fileName = $file->getFilename();
            $content = $this->files->get($file);
            $this->files->put("{$toPath}/{$fileName}", $content);
        }

        $this->info("从 [{$fromLang}] 复制到 [{$toLang}] 成功");

        return 0;
    }

    /**
     * 同步语言文件
     *
     * @param  string  $langPath  语言文件路径
     * @param  string  $baseLang  基础语言
     * @return int  退出码
     */
    protected function syncLanguageFiles(string $langPath, string $baseLang): int
    {
        $basePath = "{$langPath}/{$baseLang}";

        if (!($this->files->exists($basePath))) {
            $this->error("基础语言 [{$baseLang}] 不存在");
            return 1;
        }

        $languages = $this->files->directories($langPath);

        foreach ($languages as $language) {
            $langCode = basename($language);

            if ($langCode === $baseLang) {
                continue;
            }

            $this->info("同步语言 [{$langCode}]...");

            // 复制所有语言文件
            $baseFiles = $this->files->files($basePath);

            foreach ($baseFiles as $baseFile) {
                $fileName = $baseFile->getFilename();
                $baseContent = $this->files->get($baseFile);
                $targetFile = "{$language}/{$fileName}";

                if (!$this->files->exists($targetFile)) {
                    $this->files->put($targetFile, $baseContent);
                    $this->line("  添加文件: {$fileName}");
                } else {
                    // 合并翻译
                    $targetContent = $this->files->get($targetFile);
                    $mergedContent = $this->mergeTranslations($baseContent, $targetContent);
                    $this->files->put($targetFile, $mergedContent);
                    $this->line("  同步文件: {$fileName}");
                }
            }
        }

        $this->info('同步完成');

        return 0;
    }

    /**
     * 检查缺失的翻译
     *
     * @param  string  $langPath  语言文件路径
     * @return int  退出码
     */
    protected function checkMissingTranslations(string $langPath): int
    {
        $languages = $this->files->directories($langPath);

        if (empty($languages)) {
            $this->info('没有找到语言文件');
            return 0;
        }

        // 以第一个语言为基准
        $baseLang = basename($languages[0]);
        $basePath = "{$langPath}/{$baseLang}";

        $this->info("以 [{$baseLang}] 为基准检查缺失的翻译:");

        foreach ($languages as $language) {
            $langCode = basename($language);

            if ($langCode === $baseLang) {
                continue;
            }

            $this->line("  检查语言 [{$langCode}]:");

            $baseFiles = $this->files->files($basePath);

            foreach ($baseFiles as $baseFile) {
                $fileName = $baseFile->getFilename();
                $targetFile = "{$language}/{$fileName}";

                if (!($this->files->exists($targetFile))) {
                    $this->line("    - 缺失文件: {$fileName}");
                    continue;
                }

                // 检查缺失的翻译键
                $baseContent = $this->files->get($baseFile);
                $targetContent = $this->files->get($targetFile);

                $baseTranslations = eval('return ' . $baseContent . ';');
                $targetTranslations = eval('return ' . $targetContent . ';');

                $missingKeys = array_diff(array_keys($baseTranslations), array_keys($targetTranslations));

                if (!empty($missingKeys)) {
                    $this->line("    - 文件 {$fileName} 中缺失的键:");
                    foreach ($missingKeys as $key) {
                        $this->line("      - {$key}");
                    }
                }
            }
        }

        return 0;
    }

    /**
     * 导出语言文件为 CSV 格式
     *
     * @param  string  $langPath  语言文件路径
     * @param  string  $exportPath  导出路径
     * @return int  退出码
     */
    protected function exportLanguageFiles(string $langPath, string $exportPath): int
    {
        $languages = $this->files->directories($langPath);

        if (empty($languages)) {
            $this->info('没有找到语言文件');
            return 0;
        }

        $csvContent = "键," . implode(',', array_map('basename', $languages)) . "\n";

        // 收集所有键
        $allKeys = [];
        foreach ($languages as $language) {
            $files = $this->files->files($language);
            foreach ($files as $file) {
                $content = $this->files->get($file);
                $translations = eval('return ' . $content . ';');
                $allKeys = array_merge($allKeys, array_keys($translations));
            }
        }
        $allKeys = array_unique($allKeys);

        // 生成 CSV 内容
        foreach ($allKeys as $key) {
            $row = [$key];
            foreach ($languages as $language) {
                $translation = '';
                $files = $this->files->files($language);
                foreach ($files as $file) {
                    $content = $this->files->get($file);
                    $translations = eval('return ' . $content . ';');
                    if (isset($translations[$key])) {
                        $translation = $translations[$key];
                        break;
                    }
                }
                $row[] = $translation;
            }
            $csvContent .= implode(',', array_map(function ($value) {
                return '"' . str_replace('"', '""', $value) . '"';
            }, $row)) . "\n";
        }

        $this->files->put($exportPath, $csvContent);
        $this->info("语言文件已导出到: {$exportPath}");

        return 0;
    }

    /**
     * 从 CSV 文件导入翻译
     *
     * @param  string  $langPath  语言文件路径
     * @param  string  $importPath  导入路径
     * @return int  退出码
     */
    protected function importLanguageFiles(string $langPath, string $importPath): int
    {
        if (!($this->files->exists($importPath))) {
            $this->error("导入文件不存在: {$importPath}");
            return 1;
        }

        $csvContent = $this->files->get($importPath);
        $lines = explode("\n", $csvContent);

        if (empty($lines)) {
            $this->error('导入文件为空');
            return 1;
        }

        // 解析表头
        $headers = str_getcsv(array_shift($lines));
        array_shift($headers); // 移除第一列（键）

        // 为每种语言创建翻译数组
        $translations = [];
        foreach ($headers as $langCode) {
            $translations[$langCode] = [];
        }

        // 解析数据
        foreach ($lines as $line) {
            if (empty($line)) {
                continue;
            }
            $data = str_getcsv($line);
            $key = array_shift($data);
            foreach ($headers as $index => $langCode) {
                $translations[$langCode][$key] = $data[$index] ?? '';
            }
        }

        // 写入翻译文件
        foreach ($translations as $langCode => $langTranslations) {
            $langPath = "{$langPath}/{$langCode}";
            if (!($this->files->exists($langPath))) {
                $this->files->makeDirectory($langPath, 0755, true);
            }

            $this->files->put(
                "{$langPath}/messages.php",
                "<?php\n\nreturn " . var_export($langTranslations, true) . ";\n"
            );

            $this->info("导入语言 [{$langCode}] 成功");
        }

        return 0;
    }

    /**
     * 合并翻译
     *
     * @param  string  $baseContent  基础翻译内容
     * @param  string  $targetContent  目标翻译内容
     * @return string  合并后的翻译内容
     */
    protected function mergeTranslations(string $baseContent, string $targetContent): string
    {
        $baseTranslations = eval('return ' . $baseContent . ';');
        $targetTranslations = eval('return ' . $targetContent . ';');

        $mergedTranslations = array_merge($baseTranslations, $targetTranslations);

        return "<?php\n\nreturn " . var_export($mergedTranslations, true) . ";\n";
    }
}
