<?php

namespace Kylin\Modules\Console\Commands;

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

/**
 * 模块生成所有组件命令
 *
 * 为模块生成所有基本组件
 */
class ModuleMakeAllCommand extends Command
{
    /**
     * 命令名称和签名
     *
     * @var string
     * 
     * 命令参数说明：
     * 1. {module} - 模块名称（必填）
     *    - 数据类型：字符串
     *    - 用途：指定要生成所有基本组件的模块名称
     *    - 示例：php artisan module:make-all game
     * 
     * 命令选项说明：
     * 1. {--o|only=} - 只生成指定的组件
     *    - 简写：-o
     *    - 完整形式：--only
     *    - 数据类型：字符串
     *    - 用途：指定只生成哪些组件，多个组件用逗号分隔
     *    - 示例：php artisan module:make-all game --only=controller,model,migration
     * 
     * 2. {--e|except=} - 排除指定的组件
     *    - 简写：-e
     *    - 完整形式：--except
     *    - 数据类型：字符串
     *    - 用途：指定排除哪些组件，多个组件用逗号分隔
     *    - 示例：php artisan module:make-all game --except=controller,model
     */
    protected $signature = 'module:make-all {module : 模块名称} {--o|only= : 只生成指定的组件，多个组件用逗号分隔（如：controller,model,migration）} {--e|except= : 排除指定的组件，多个组件用逗号分隔（如：controller,model,migration）}';

    /**
     * 命令描述
     *
     * @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');
        $only = $this->option('only') ? explode(',', $this->option('only')) : [];
        $except = $this->option('except') ? explode(',', $this->option('except')) : [];

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

        $modulePath = $module->getPath();
        $srcPath = "{$modulePath}/src";

        // 生成首字母大写的模块名称
        $studlyModuleName = ucfirst($moduleName);
        // 生成完整的命名空间，包含供应商名称
        $fullNamespace = "Kylin\\{$studlyModuleName}";
        
        // 定义要生成的组件
        $components = [
            'controller' => [
                'path' => "{$srcPath}/Http/Controllers",
                'file' => "{$studlyModuleName}Controller.php",
                'stub' => 'controller.plain.stub',
                'namespace' => "{$fullNamespace}\Http\Controllers",
                'class' => "{$studlyModuleName}Controller"
            ],
            'model' => [
                'path' => "{$srcPath}/Models",
                'file' => "{$studlyModuleName}.php",
                'stub' => 'model.plain.stub',
                'namespace' => "{$fullNamespace}\Models",
                'class' => "{$studlyModuleName}"
            ],
            'migration' => [
                'path' => "{$modulePath}/database/migrations",
                'file' => date('Y_m_d_His') . "_create_{$moduleName}_table.php",
                'stub' => 'migration.create.stub',
                'namespace' => '',
                'class' => 'Create' . $studlyModuleName . 'Table',
                'table' => strtolower($moduleName)
            ],
            'seeder' => [
                'path' => "{$modulePath}/database/seeders",
                'file' => "{$studlyModuleName}Seeder.php",
                'stub' => 'seeder.stub',
                'namespace' => "{$fullNamespace}\Database\Seeders",
                'class' => "{$studlyModuleName}Seeder"
            ],
            'factory' => [
                'path' => "{$modulePath}/database/factories",
                'file' => "{$studlyModuleName}Factory.php",
                'stub' => 'factory.stub',
                'namespace' => "{$fullNamespace}\Database\Factories",
                'class' => "{$studlyModuleName}Factory",
                'model' => $studlyModuleName
            ],
            'middleware' => [
                'path' => "{$srcPath}/Http/Middleware",
                'file' => "{$studlyModuleName}Middleware.php",
                'stub' => 'middleware.stub',
                'namespace' => "{$fullNamespace}\Http\Middleware",
                'class' => "{$studlyModuleName}Middleware"
            ],
            'request' => [
                'path' => "{$srcPath}/Http/Requests",
                'file' => "{$studlyModuleName}Request.php",
                'stub' => 'request.stub',
                'namespace' => "{$fullNamespace}\Http\Requests",
                'class' => "{$studlyModuleName}Request"
            ],
            'command' => [
                'path' => "{$srcPath}/Console/Commands",
                'file' => "{$studlyModuleName}Command.php",
                'stub' => 'command.stub',
                'namespace' => "{$fullNamespace}\Console\Commands",
                'class' => "{$studlyModuleName}Command",
                'signature' => "{$moduleName}:command"
            ],
            'policy' => [
                'path' => "{$srcPath}/Policies",
                'file' => "{$studlyModuleName}Policy.php",
                'stub' => 'policy.stub',
                'namespace' => "{$fullNamespace}\Policies",
                'class' => "{$studlyModuleName}Policy"
            ],
            'rule' => [
                'path' => "{$srcPath}/Rules",
                'file' => "{$studlyModuleName}Rule.php",
                'stub' => 'rule.stub',
                'namespace' => "{$fullNamespace}\Rules",
                'class' => "{$studlyModuleName}Rule"
            ],
            'mail' => [
                'path' => "{$srcPath}/Mail",
                'file' => "{$studlyModuleName}Mail.php",
                'stub' => 'mail.stub',
                'namespace' => "{$fullNamespace}\Mail",
                'class' => "{$studlyModuleName}Mail",
                'module' => $moduleName
            ],
            'notification' => [
                'path' => "{$srcPath}/Notifications",
                'file' => "{$studlyModuleName}Notification.php",
                'stub' => 'notification.stub',
                'namespace' => "{$fullNamespace}\Notifications",
                'class' => "{$studlyModuleName}Notification"
            ],
            'resource' => [
                'path' => "{$srcPath}/Http/Resources",
                'file' => "{$studlyModuleName}Resource.php",
                'stub' => 'resource.stub',
                'namespace' => "{$fullNamespace}\Http\Resources",
                'class' => "{$studlyModuleName}Resource"
            ],
            'component' => [
                'path' => "{$srcPath}/View/Components",
                'file' => "{$studlyModuleName}Component.php",
                'stub' => 'component.stub',
                'namespace' => "{$fullNamespace}\View\Components",
                'class' => "{$studlyModuleName}Component",
                'module' => $moduleName
            ],
            'test' => [
                'path' => "{$modulePath}/tests",
                'file' => "{$studlyModuleName}Test.php",
                'stub' => 'test.feature.stub',
                'namespace' => "{$fullNamespace}\Tests",
                'class' => "{$studlyModuleName}Test"
            ],
            'event' => [
                'path' => "{$srcPath}/Events",
                'file' => "{$studlyModuleName}Event.php",
                'stub' => 'event.stub',
                'namespace' => "{$fullNamespace}\Events",
                'class' => "{$studlyModuleName}Event"
            ],
            'listener' => [
                'path' => "{$srcPath}/Listeners",
                'file' => "{$studlyModuleName}Listener.php",
                'stub' => 'listener.stub',
                'namespace' => "{$fullNamespace}\Listeners",
                'class' => "{$studlyModuleName}Listener"
            ],
            'observer' => [
                'path' => "{$srcPath}/Observers",
                'file' => "{$studlyModuleName}Observer.php",
                'stub' => 'observer.stub',
                'namespace' => "{$fullNamespace}\Observers",
                'class' => "{$studlyModuleName}Observer"
            ],
            'job' => [
                'path' => "{$srcPath}/Jobs",
                'file' => "{$studlyModuleName}Job.php",
                'stub' => 'job.stub',
                'namespace' => "{$fullNamespace}\Jobs",
                'class' => "{$studlyModuleName}Job"
            ],
            'scope' => [
                'path' => "{$srcPath}/Models/Scopes",
                'file' => "{$studlyModuleName}Scope.php",
                'stub' => 'scope.stub',
                'namespace' => "{$fullNamespace}\Models\Scopes",
                'class' => "{$studlyModuleName}Scope"
            ],
            'trait' => [
                'path' => "{$srcPath}/Traits",
                'file' => "{$studlyModuleName}Trait.php",
                'stub' => 'trait.stub',
                'namespace' => "{$fullNamespace}\Traits",
                'class' => "{$studlyModuleName}Trait"
            ],
            'interface' => [
                'path' => "{$srcPath}/Interfaces",
                'file' => "{$studlyModuleName}Interface.php",
                'stub' => 'interface.stub',
                'namespace' => "{$fullNamespace}\Interfaces",
                'class' => "{$studlyModuleName}Interface"
            ],
            'enum' => [
                'path' => "{$srcPath}/Enums",
                'file' => "{$studlyModuleName}Enum.php",
                'stub' => 'enum.stub',
                'namespace' => "{$fullNamespace}\Enums",
                'class' => "{$studlyModuleName}Enum"
            ],
            'provider' => [
                'path' => "{$srcPath}/Providers",
                'file' => "{$studlyModuleName}ServiceProvider.php",
                'stub' => 'provider.stub',
                'namespace' => "{$fullNamespace}\Providers",
                'class' => "{$studlyModuleName}ServiceProvider"
            ],
            'exception' => [
                'path' => "{$srcPath}/Exceptions",
                'file' => "{$studlyModuleName}Exception.php",
                'stub' => 'exception.stub',
                'namespace' => "{$fullNamespace}\Exceptions",
                'class' => "{$studlyModuleName}Exception"
            ],
            'helper' => [
                'path' => "{$srcPath}/Helpers",
                'file' => "{$studlyModuleName}Helper.php",
                'stub' => 'helper.stub',
                'name' => $moduleName
            ],
            'contract' => [
                'path' => "{$srcPath}/Contracts",
                'file' => "{$studlyModuleName}Contract.php",
                'stub' => 'contract.stub',
                'namespace' => "{$fullNamespace}\Contracts",
                'class' => "{$studlyModuleName}Contract"
            ],
            'service' => [
                'path' => "{$srcPath}/Services",
                'file' => "{$studlyModuleName}Service.php",
                'stub' => 'service.stub',
                'namespace' => "{$fullNamespace}\Services",
                'class' => "{$studlyModuleName}Service"
            ],
            'repository' => [
                'path' => "{$srcPath}/Repositories",
                'file' => "{$studlyModuleName}Repository.php",
                'stub' => 'repository.stub',
                'namespace' => "{$fullNamespace}\Repositories",
                'class' => "{$studlyModuleName}Repository"
            ],

            'route' => [
                'path' => "{$modulePath}/routes",
                'file' => "web.php",
                'stub' => 'routes.web.stub',
                'namespace' => "{$fullNamespace}\Http\Controllers"
            ],
            'api-route' => [
                'path' => "{$modulePath}/routes",
                'file' => "api.php",
                'stub' => 'routes.api.stub',
                'namespace' => "{$fullNamespace}\Http\Controllers\Api"
            ],
            'view' => [
                'path' => "{$modulePath}/resources/views",
                'file' => "index.blade.php",
                'stub' => 'views.index.stub',
                'name' => $moduleName
            ],
            'lang' => [
                'path' => "{$modulePath}/resources/lang/zh_CN",
                'file' => "{$moduleName}.php",
                'stub' => 'lang.stub'
            ],
            'broadcast' => [
                'path' => "{$srcPath}/Broadcasting",
                'file' => "{$studlyModuleName}Channel.php",
                'stub' => 'broadcast.stub',
                'namespace' => "{$studlyModuleName}\Broadcasting",
                'class' => "{$studlyModuleName}Channel"
            ],
            'subscriber' => [
                'path' => "{$srcPath}/Listeners",
                'file' => "{$studlyModuleName}Subscriber.php",
                'stub' => 'subscriber.stub',
                'namespace' => "{$studlyModuleName}\Listeners",
                'class' => "{$studlyModuleName}Subscriber"
            ],
            'cast' => [
                'path' => "{$srcPath}/Casts",
                'file' => "{$studlyModuleName}Cast.php",
                'stub' => 'cast.stub',
                'namespace' => "{$studlyModuleName}\Casts",
                'class' => "{$studlyModuleName}Cast"
            ],
            'inertia' => [
                'path' => "{$modulePath}/resources/js/Pages",
                'file' => "Index.vue",
                'stub' => 'inertia.page.stub',
                'module' => $moduleName
            ],
        ];

        // 过滤组件
        if (!empty($only)) {
            $components = array_intersect_key($components, array_flip($only));
        }

        if (!empty($except)) {
            $components = array_diff_key($components, array_flip($except));
        }

        // 生成组件
        foreach ($components as $name => $component) {
            // 确保目录存在
            if (!($this->files->exists($component['path']))) {
                $this->files->makeDirectory($component['path'], 0755, true);
                $this->info("创建目录: {$component['path']}");
            }

            $filePath = "{$component['path']}/{$component['file']}";

            // 检查文件是否存在
            if ($this->files->exists($filePath)) {
                $this->warn("文件 [{$component['file']}] 已存在，跳过");
                continue;
            }

            // 生成文件内容
            $content = $this->buildContent($component);

            // 生成文件
            $this->files->put($filePath, $content);
            $this->info("创建文件: {$filePath}");
        }

        $this->info("模块 [{$moduleName}] 的所有组件生成完成！");

        return 0;
    }

    /**
     * 构建文件内容
     */
    protected function buildContent(array $component): string
    {
        $stubPath = __DIR__ . '/../../../stubs/' . $component['stub'];
        $stub = $this->files->get($stubPath);

        // 获取作者和版本信息
        $authorName = $this->app['config']->get('modules.defaults.author_name', '王康');
        $authorEmail = $this->app['config']->get('modules.defaults.author_email', 'earl.k.wang@wangk.cn');
        $version = $this->app['config']->get('modules.defaults.version', '1.0.0');

        // 替换通用变量
        if (isset($component['namespace'])) {
            $stub = str_replace('{{ namespace }}', $component['namespace'], $stub);
            $stub = str_replace('{{namespace}}', $component['namespace'], $stub);
        }

        if (isset($component['class'])) {
            $stub = str_replace('{{ class }}', $component['class'], $stub);
            $stub = str_replace('{{class}}', $component['class'], $stub);
        }

        // 替换特定变量
        if (isset($component['signature'])) {
            $stub = str_replace('{{ signature }}', $component['signature'], $stub);
            $stub = str_replace('{{signature}}', $component['signature'], $stub);
        }

        if (isset($component['table'])) {
            $stub = str_replace('{{ table }}', $component['table'], $stub);
            $stub = str_replace('{{table}}', $component['table'], $stub);
        }

        if (isset($component['model'])) {
            $stub = str_replace('{{ model }}', $component['model'], $stub);
            $stub = str_replace('{{model}}', $component['model'], $stub);
            $modelNamespace = $component['namespace'] . '\\' . $component['model'];
            $stub = str_replace('{{ modelNamespace }}', $modelNamespace, $stub);
            $stub = str_replace('{{modelNamespace}}', $modelNamespace, $stub);
        }

        if (isset($component['module'])) {
            $stub = str_replace('{{ module }}', $component['module'], $stub);
        }

        if (isset($component['name'])) {
            $stub = str_replace('{{ name }}', $component['name'], $stub);
            $stub = str_replace('{{name}}', $component['name'], $stub);
        }

        if (isset($component['uppercaseName'])) {
            $stub = str_replace('{{ uppercaseName }}', $component['uppercaseName'], $stub);
        }

        // 替换作者和版本信息
        $stub = str_replace('{{AUTHOR_NAME}}', $authorName, $stub);
        $stub = str_replace('{{AUTHOR_EMAIL}}', $authorEmail, $stub);
        $stub = str_replace('{{VERSION}}', $version, $stub);

        return $stub;
    }
}