<?php

namespace Kylin\Modules\Console\Commands;

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

/**
 * 模块复制命令
 *
 * 基于现有模块创建新模块
 */
class ModuleCopyCommand extends Command
{
    /**
     * 命令名称和签名
     *
     * @var string
     * 
     * 命令参数说明：
     * 1. {from} - 源模块名称（必填）
     *    - 数据类型：字符串
     *    - 用途：指定要复制的源模块名称
     *    - 示例：php artisan module:copy game user
     * 
     * 2. {to} - 目标模块名称（必填）
     *    - 数据类型：字符串
     *    - 用途：指定要创建的目标模块名称
     *    - 示例：php artisan module:copy game user
     * 
     * 命令选项说明：
     * 1. {--force} - 强制覆盖现有模块
     *    - 完整形式：--force
     *    - 用途：强制覆盖已存在的目标模块
     *    - 示例：php artisan module:copy game user --force
     */
    protected $signature = 'module:copy {from : 源模块名称} {to : 目标模块名称} {--force : 强制覆盖现有模块}';

    /**
     * 命令描述
     *
     * @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
    {
        $from = (string) $this->argument('from');
        $to = (string) $this->argument('to');
        $force = (bool) $this->option('force');

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

        // 检查目标模块是否已存在
        $targetModule = $this->moduleManager->get($to);
        if ($targetModule && !$force) {
            $this->error("目标模块 [{$to}] 已存在。使用 --force 选项强制覆盖。");
            return 1;
        }

        // 获取源模块路径和目标模块路径
        $sourcePath = $sourceModule->getPath();
        $targetPath = $this->moduleManager->getPath() . '/' . $to;

        // 如果目标模块已存在且强制覆盖，则删除它
        if ($targetModule && $force) {
            $this->info("正在删除现有模块 [{$to}]...");
            $this->files->deleteDirectory($targetPath);
        }

        try {
            $this->info("正在从模块 [{$from}] 复制到模块 [{$to}]...");

            // 复制目录结构
            $this->copyDirectory($sourcePath, $targetPath, $from, $to);

            // 清除模块缓存
            $this->call('module:clear-cache');

            $this->info("模块 [{$from}] 已成功复制为模块 [{$to}]。");
            $this->info("提示：请根据需要修改新模块的配置和代码。");

            return 0;
        } catch (\Exception $e) {
            $this->error("复制模块失败: {$e->getMessage()}");
            return 1;
        }
    }

    /**
     * 复制目录并替换模块名称
     *
     * @param  string  $source  源目录
     * @param  string  $target  目标目录
     * @param  string  $fromName  源模块名称
     * @param  string  $toName  目标模块名称
     */
    protected function copyDirectory(string $source, string $target, string $fromName, string $toName): void
    {
        if (!$this->files->isDirectory($source)) {
            return;
        }

        // 创建目标目录
        if (!$this->files->exists($target)) {
            $this->files->makeDirectory($target, 0755, true);
        }

        // 获取源目录中的文件和子目录
        $files = $this->files->files($source);
        $directories = $this->files->directories($source);

        // 复制文件并替换内容中的模块名称
        foreach ($files as $file) {
            $targetFile = $target . '/' . $file->getFilename();
            $content = $this->files->get($file);

            // 替换内容中的模块名称
            $content = $this->replaceModuleNames($content, $fromName, $toName);

            $this->files->put($targetFile, $content);
        }

        // 递归复制子目录
        foreach ($directories as $directory) {
            $dirName = basename($directory);
            $targetDir = $target . '/' . $dirName;
            $this->copyDirectory($directory, $targetDir, $fromName, $toName);
        }
    }

    /**
     * 替换内容中的模块名称
     *
     * @param  string  $content  文件内容
     * @param  string  $fromName  源模块名称
     * @param  string  $toName  目标模块名称
     * @return string  替换后的内容
     */
    protected function replaceModuleNames(string $content, string $fromName, string $toName): string
    {
        // 转换为驼峰命名
        $fromStudly = str_replace(' ', '', ucwords(str_replace('-', ' ', $fromName)));
        $toStudly = str_replace(' ', '', ucwords(str_replace('-', ' ', $toName)));

        // 转换为小写短横线命名
        $fromKebab = strtolower(str_replace(' ', '-', ucwords(str_replace('-', ' ', $fromName))));
        $toKebab = strtolower(str_replace(' ', '-', ucwords(str_replace('-', ' ', $toName))));

        // 转换为小写下划线命名
        $fromSnake = strtolower(str_replace(' ', '_', ucwords(str_replace('-', ' ', $fromName))));
        $toSnake = strtolower(str_replace(' ', '_', ucwords(str_replace('-', ' ', $toName))));

        // 替换各种格式的模块名称
        $replacements = [
            $fromStudly => $toStudly,
            $fromKebab => $toKebab,
            $fromSnake => $toSnake,
            $fromName => $toName,
        ];

        foreach ($replacements as $search => $replace) {
            if (!empty($search)) {
                $content = str_replace($search, $replace, $content);
            }
        }

        return $content;
    }
}
