<?php

namespace Kylin\Modules\Console\Commands;

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

/**
 * 创建模块请求命令
 *
 * 用于为指定模块创建新的请求类
 */
class ModuleMakeRequestCommand extends Command
{
    /**
     * 命令名称和签名
     *
     * @var string
     * 
     * 命令参数说明：
     * 1. {module} - 模块名称（必填）
     *    - 数据类型：字符串
     *    - 用途：指定请求类所属的模块名称
     *    - 示例：php artisan module:make-request game StoreUserRequest
     * 
     * 2. {name} - 请求类名称（必填）
     *    - 数据类型：字符串
     *    - 用途：指定要创建的请求类名称
     *    - 示例：php artisan module:make-request game StoreUserRequest
     */
    protected $signature = 'module:make-request {module : 模块名称} {name : 请求类名称}';


    /**
     * 命令描述
     *
     * @var string
     */
    protected $description = '为模块创建新的请求类';

    /**
     * 创建新命令实例
     *
     * @param  Filesystem  $files  文件系统实例
     * @param  ModuleManager  $moduleManager  模块管理器实例
     */
    public function __construct(
        private readonly Filesystem $files,
        private readonly ModuleManager $moduleManager
    ) {
        parent::__construct();
    }

    /**
     * 执行控制台命令
     */
    public function handle(): int
    {
        $moduleName = (string) $this->argument('module');
        $requestName = (string) $this->argument('name');

        $module = $this->moduleManager->get($moduleName);

        if (!$module) {
            $this->error("模块 [{$moduleName}] 不存在。");
            return 1;
        }

        $requestPath = $this->getRequestPath($module, $requestName);
        $requestNamespace = $this->getRequestNamespace($module, $requestName);
        $requestClass = $this->getRequestClass($requestName);

        if ($this->files->exists($requestPath)) {
            $this->error("请求 [{$requestClass}] 在模块 [{$moduleName}] 中已存在。");
            return 1;
        }

        if (!$this->files->isDirectory(dirname($requestPath))) {
            $this->files->makeDirectory(dirname($requestPath), 0755, true);
        }

        $stub = $this->getStub();
        $content = $this->replaceStubVariables($stub, $requestNamespace, $requestClass);

        $this->files->put($requestPath, $content);

        $this->info("请求 [{$requestClass}] 在模块 [{$moduleName}] 中创建成功！");
        $this->info("请求路径: {$requestPath}");

        return 0;
    }

    /**
     * 获取请求路径
     *
     * @param  \Kylin\Modules\Module  $module  模块实例
     * @param  string  $requestName  请求名称
     * @return string
     */
    protected function getRequestPath($module, string $requestName): string
    {
        $requestPath = str_replace('\\', '/', $requestName);
        return $module->getPath('src/Http/Requests/' . $requestPath . '.php');
    }

    /**
     * 获取请求命名空间
     *
     * @param  \Kylin\Modules\Module  $module  模块实例
     * @param  string  $requestName  请求名称
     * @return string
     */
    protected function getRequestNamespace($module, string $requestName): string
    {
        $namespace = $module->getNamespace();
        $requestPath = str_replace('/', '\\', dirname(str_replace('\\', '/', $requestName)));
        
        if ($requestPath != '.') {
            $namespace .= '\\Http\\Requests\\' . $requestPath;
        } else {
            $namespace .= '\\Http\\Requests';
        }
        
        return $namespace;
    }

    /**
     * 获取请求类名
     *
     * @param  string  $requestName  请求名称
     * @return string
     */
    protected function getRequestClass(string $requestName): string
    {
        return basename(str_replace('\\', '/', $requestName));
    }

    /**
     * 获取模板文件
     *
     * @return string
     */
    protected function getStub(): string
    {
        $stubPath = __DIR__ . '/../../../stubs/request.stub';
        return $this->files->get($stubPath);
    }

    /**
     * 替换模板变量
     *
     * @param  string  $stub  模板内容
     * @param  string  $namespace  命名空间
     * @param  string  $class  类名
     * @return string
     */
    protected function replaceStubVariables(string $stub, string $namespace, string $class): string
    {
        $stub = str_replace('{{namespace}}', $namespace, $stub);
        $stub = str_replace('{{class}}', $class, $stub);

        return $stub;
    }
}