<?php

namespace Kylin\Modules\Console\Commands;

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

/**
 * 创建模块中间件命令
 *
 * 用于为指定模块创建新的中间件类
 */
class ModuleMakeMiddlewareCommand extends Command
{
    /**
     * 命令名称和签名
     *
     * @var string
     * 
     * 命令参数说明：
     * 1. {module} - 模块名称（必填）
     *    - 数据类型：字符串
     *    - 用途：指定中间件所属的模块名称
     *    - 示例：php artisan module:make-middleware game CustomMiddleware
     * 
     * 2. {name} - 中间件名称（必填）
     *    - 数据类型：字符串
     *    - 用途：指定要创建的中间件名称
     *    - 示例：php artisan module:make-middleware game CustomMiddleware
     */
    protected $signature = 'module:make-middleware {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');
        $middlewareName = (string) $this->argument('name');

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

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

        $middlewarePath = $this->getMiddlewarePath($module, $middlewareName);
        $middlewareNamespace = $this->getMiddlewareNamespace($module, $middlewareName);
        $middlewareClass = $this->getMiddlewareClass($middlewareName);

        if ($this->files->exists($middlewarePath)) {
            $this->error("中间件 [{$middlewareClass}] 在模块 [{$moduleName}] 中已存在。");
            return 1;
        }

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

        $stub = $this->getStub();
        $content = $this->replaceStubVariables($stub, $middlewareNamespace, $middlewareClass);

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

        $this->info("中间件 [{$middlewareClass}] 在模块 [{$moduleName}] 中创建成功！");
        $this->info("中间件路径: {$middlewarePath}");

        return 0;
    }

    /**
     * 获取中间件路径
     *
     * @param  \Kylin\Modules\Module  $module  模块实例
     * @param  string  $middlewareName  中间件名称
     * @return string
     */
    protected function getMiddlewarePath($module, string $middlewareName): string
    {
        $middlewarePath = str_replace('\\', '/', $middlewareName);
        return $module->getPath('src/Http/Middleware/' . $middlewarePath . '.php');
    }

    /**
     * 获取中间件命名空间
     *
     * @param  \Kylin\Modules\Module  $module  模块实例
     * @param  string  $middlewareName  中间件名称
     * @return string
     */
    protected function getMiddlewareNamespace($module, string $middlewareName): string
    {
        $namespace = $module->getNamespace();
        $middlewarePath = str_replace('/', '\\', dirname(str_replace('\\', '/', $middlewareName)));
        
        if ($middlewarePath != '.') {
            $namespace .= '\\Http\\Middleware\\' . $middlewarePath;
        } else {
            $namespace .= '\\Http\\Middleware';
        }
        
        return $namespace;
    }

    /**
     * 获取中间件类名
     *
     * @param  string  $middlewareName  中间件名称
     * @return string
     */
    protected function getMiddlewareClass(string $middlewareName): string
    {
        return basename(str_replace('\\', '/', $middlewareName));
    }

    /**
     * 获取模板文件
     *
     * @return string
     */
    protected function getStub(): string
    {
        $stubPath = __DIR__ . '/../../../stubs/middleware.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;
    }
}