<?php

namespace Kylin\Modules\Console\Commands;

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

/**
 * 模块导入命令
 *
 * 从压缩文件导入模块
 */
class ModuleImportCommand extends Command
{
    /**
     * 命令名称和签名
     *
     * @var string
     * 
     * 命令参数说明：
     * 1. {file} - 模块压缩文件路径（必填）
     *    - 数据类型：字符串
     *    - 用途：指定要导入的模块压缩文件路径
     *    - 示例：php artisan module:import /path/to/game.zip
     * 
     * 命令选项说明：
     * 1. {--force} - 强制覆盖现有模块
     *    - 完整形式：--force
     *    - 用途：强制覆盖已存在的模块
     *    - 示例：php artisan module:import /path/to/game.zip --force
     * 
     * 2. {--name=} - 模块名称
     *    - 完整形式：--name
     *    - 数据类型：字符串
     *    - 用途：指定模块名称，默认为压缩文件名
     *    - 示例：php artisan module:import /path/to/game.zip --name=game
     */
    protected $signature = 'module:import {file : 模块压缩文件路径} {--force : 强制覆盖现有模块} {--name= : 模块名称，默认为压缩文件名}';

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

        // 检查文件是否存在
        if (!$this->files->exists($file)) {
            $this->error("文件 [{$file}] 未找到。");
            return 1;
        }

        // 检查文件是否为 ZIP 文件
        if (pathinfo($file, PATHINFO_EXTENSION) !== 'zip') {
            $this->error("文件 [{$file}] 不是有效的 ZIP 文件。");
            return 1;
        }

        // 从文件名提取模块名称（如果未指定）
        if (!$name) {
            $name = pathinfo($file, PATHINFO_FILENAME);
        }

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

        $modulePath = $this->moduleManager->getPath() . '/' . $name;

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

        try {
            $this->info("正在从文件 [{$file}] 导入模块...");

            // 创建临时目录
            $tempDir = sys_get_temp_dir() . '/module-import-' . uniqid();
            $this->files->makeDirectory($tempDir, 0755, true);

            // 解压 ZIP 文件
            $this->extractZipArchive($file, $tempDir);

            // 找到模块根目录（处理可能的嵌套目录）
            $moduleRoot = $this->findModuleRoot($tempDir);

            // 确保模块目录存在
            if (!$this->files->exists($modulePath)) {
                $this->files->makeDirectory($modulePath, 0755, true);
            }

            // 复制模块文件到目标目录
            $this->copyDirectory($moduleRoot, $modulePath);

            // 清理临时目录
            $this->files->deleteDirectory($tempDir);

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

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

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

    /**
     * 解压 ZIP 压缩文件
     *
     * @param  string  $file  ZIP 文件路径
     * @param  string  $target  目标目录
     * @throws \Exception
     */
    protected function extractZipArchive(string $file, string $target): void
    {
        $zip = new \ZipArchive();

        if (!$zip->open($file)) {
            throw new \Exception("无法打开压缩文件: {$file}");
        }

        if (!$zip->extractTo($target)) {
            throw new \Exception("无法解压文件: {$file}");
        }

        if (!$zip->close()) {
            throw new \Exception("无法关闭压缩文件: {$file}");
        }
    }

    /**
     * 找到模块根目录
     *
     * @param  string  $path  临时目录路径
     * @return string  模块根目录路径
     * @throws \Exception
     */
    protected function findModuleRoot(string $path): string
    {
        $files = $this->files->files($path);
        $directories = $this->files->directories($path);

        // 检查是否直接包含 composer.json 文件
        foreach ($files as $file) {
            if ($file->getFilename() === 'composer.json') {
                return $path;
            }
        }

        // 如果只有一个子目录，检查该目录
        if (count($directories) === 1 && count($files) === 0) {
            $subDir = $directories[0];
            $subDirFiles = $this->files->files($subDir);
            
            foreach ($subDirFiles as $file) {
                if ($file->getFilename() === 'composer.json') {
                    return $subDir;
                }
            }

            return $subDir;
        }

        return $path;
    }

    /**
     * 复制目录
     *
     * @param  string  $source  源目录
     * @param  string  $target  目标目录
     */
    protected function copyDirectory(string $source, string $target): 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();
            $this->files->copy($file, $targetFile);
        }

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