<?php

namespace Kylin\Modules\Console\Commands;

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

/**
 * 模块初始化命令
 *
 * 初始化模块目录结构，确保模块目录结构符合标准
 */
class ModuleInitCommand extends Command
{
    /**
     * 命令名称和签名
     *
     * @var string
     * 
     * 命令参数说明：
     * 1. {module} - 模块名称（必填）
     *    - 数据类型：字符串
     *    - 用途：指定要初始化的模块名称
     *    - 示例：php artisan module:init game
     * 
     * 命令选项说明：
     * 1. {--f|force} - 强制初始化，覆盖现有文件
     *    - 简写：-f
     *    - 完整形式：--force
     *    - 用途：强制初始化，覆盖现有文件
     *    - 示例：php artisan module:init game -f
     * 
     * 2. {--t|template=} - 初始化模板
     *    - 简写：-t
     *    - 完整形式：--template
     *    - 数据类型：字符串
     *    - 用途：指定初始化模板（可选）
     *    - 示例：php artisan module:init game -t=api
     */
    protected $signature = 'module:init {module : 模块名称} {--f|force : 强制初始化，覆盖现有文件} {--t|template= : 初始化模板（可选）}';


    /**
     * 命令描述
     *
     * @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');
        $force = $this->option('force');
        $template = $this->option('template');

        // 检查模块是否存在
        $module = $this->moduleManager->get($moduleName);
        $modulePath = $module ? $module->getPath() : $this->moduleManager->getModulePath($moduleName);

        // 检查模块路径
        if (!$this->files->exists($modulePath)) {
            $this->files->makeDirectory($modulePath, 0755, true);
            $this->info("创建模块目录: {$modulePath}");
        } elseif (!$force) {
            $this->error("模块 [{$moduleName}] 已存在，请使用 --force 选项强制初始化");
            return 1;
        }

        $this->info("正在初始化模块 [{$moduleName}]...");

        // 初始化目录结构
        $this->initDirectoryStructure($modulePath, $moduleName);

        // 初始化配置文件
        $this->initConfigurationFiles($modulePath, $moduleName);

        $this->info("模块 [{$moduleName}] 初始化完成");

        return 0;
    }

    /**
     * 初始化目录结构
     *
     * @param  string  $modulePath  模块路径
     * @param  string  $moduleName  模块名称
     */
    protected function initDirectoryStructure(string $modulePath, string $moduleName): void
    {
        $directories = [
            'src/Console/Commands',
            'src/Http/Controllers',
            'src/Http/Middleware',
            'src/Http/Requests',
            'src/Models',
            'src/Providers',
            'config',
            'database/migrations',
            'database/seeders',
            'database/factories',
            'resources/views',
            'resources/lang',
            'routes',
        ];

        foreach ($directories as $directory) {
            $dirPath = "{$modulePath}/{$directory}";
            if (!$this->files->exists($dirPath)) {
                $this->files->makeDirectory($dirPath, 0755, true);
                $this->line("创建目录: {$directory}");
            }
        }
    }

    /**
     * 初始化配置文件
     *
     * @param  string  $modulePath  模块路径
     * @param  string  $moduleName  模块名称
     */
    protected function initConfigurationFiles(string $modulePath, string $moduleName): void
    {
        // 初始化 composer.json 文件
        $this->initComposerFile($modulePath, $moduleName);

        // 初始化模块服务提供者
        $this->initServiceProvider($modulePath, $moduleName);

        // 初始化路由文件
        $this->initRouteFile($modulePath, $moduleName);
    }

    /**
     * 初始化 composer.json 文件
     *
     * @param  string  $modulePath  模块路径
     * @param  string  $moduleName  模块名称
     */
    protected function initComposerFile(string $modulePath, string $moduleName): void
    {
        $composerPath = "{$modulePath}/composer.json";
        $studlyModuleName = Str::studly($moduleName);
        $baseNamespace = $this->app['config']->get('modules.defaults.namespace', 'Kylin');
        $namespace = "{$baseNamespace}\\{$studlyModuleName}";

        // 使用 "vendor/lower-name" 格式作为包名
        $vendor = strtolower($baseNamespace);
        $lowerName = strtolower($moduleName);
        $packageName = "{$vendor}/{$lowerName}";
        
        $moduleNamespace = $this->app['config']->get('modules.defaults.namespace', 'Kylin');
        $appFolderName = 'src';
        
        $composerContent = [
            'name' => "{$packageName}",
            'description' => "{$studlyModuleName} module",
            'type' => 'library',
            'keywords' => [
                'laravel',
                'module',
                "{$vendor}/{$lowerName}"
            ],
            'license' => 'MIT',
            'authors' => [
                [
                    'name' => $this->app['config']->get('app.name'),
                    'email' => ''
                ]
            ],
            'require' => [
                'php' => '^8.5',
            ],
            'autoload' => [
                'psr-4' => [
                    "{$moduleNamespace}\\{$studlyModuleName}\\" => "{$appFolderName}/",
                    "{$moduleNamespace}\\{$studlyModuleName}\\Database\\Factories\\" => 'database/factories/',
                    "{$moduleNamespace}\\{$studlyModuleName}\\Database\\Seeders\\" => 'database/seeders/'
                ],
            ],
            'extra' => [
                'laravel' => [
                    'providers' => [
                        "{$moduleNamespace}\\{$studlyModuleName}\\Providers\\AppServiceProvider"
                    ],
                    'aliases' => [
                    ]
                ]
            ],
            'config' => [
                'sort-packages' => true
            ],
            'minimum-stability' => 'dev',
            'prefer-stable' => true
        ];

        if (!$this->files->exists($composerPath)) {
            $this->files->put($composerPath, json_encode($composerContent, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
            $this->line("创建 composer.json 文件");
        }
    }

    /**
     * 初始化模块服务提供者
     *
     * @param  string  $modulePath  模块路径
     * @param  string  $moduleName  模块名称
     */
    protected function initServiceProvider(string $modulePath, string $moduleName): void
    {
        $providerPath = "{$modulePath}/src/Providers/AppServiceProvider.php";
        $studlyModuleName = Str::studly($moduleName);
        $baseNamespace = $this->app['config']->get('modules.defaults.namespace', 'Kylin');
        $namespace = "{$baseNamespace}\\{$studlyModuleName}";

        $providerContent = <<<PHP
<?php

namespace {$namespace}\Providers;

use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    /**
     * 启动模块服务
     */
    public function boot()
    {
        this->registerRoutes();
        this->registerViews();
        this->registerTranslations();
        this->registerConfig();
    }

    /**
     * 注册模块路由
     */
    protected function registerRoutes()
    {
        this->loadRoutesFrom(__DIR__ . '/../../routes/web.php');
    }

    /**
     * 注册模块视图
     */
    protected function registerViews()
    {
        this->loadViewsFrom(__DIR__ . '/../../resources/views', '{$moduleName}');
    }

    /**
     * 注册模块翻译
     */
    protected function registerTranslations()
    {
        this->loadTranslationsFrom(__DIR__ . '/../../resources/lang', '{$moduleName}');
    }

    /**
     * 注册模块配置
     */
    protected function registerConfig()
    {
        this->mergeConfigFrom(
            __DIR__ . '/../../config/config.php',
            '{$moduleName}'
        );
    }
}
PHP;

        if (!$this->files->exists($providerPath)) {
            $this->files->put($providerPath, $providerContent);
            $this->line("创建服务提供者文件: AppServiceProvider.php");
        }
    }

    /**
     * 初始化路由文件
     *
     * @param  string  $modulePath  模块路径
     * @param  string  $moduleName  模块名称
     */
    protected function initRouteFile(string $modulePath, string $moduleName): void
    {
        $routePath = "{$modulePath}/routes/web.php";
        $studlyModuleName = Str::studly($moduleName);
        $baseNamespace = $this->app['config']->get('modules.defaults.namespace', 'Kylin');
        $namespace = "{$baseNamespace}\\{$studlyModuleName}";

        $routeContent = <<<PHP
<?php

use Illuminate\Support\Facades\Route;
use {$namespace}\Http\Controllers\{$studlyModuleName}Controller;

Route::group([
    'prefix' => '{$moduleName}',
    'namespace' => '{$namespace}\Http\Controllers',
], function () {
    Route::get('/', [{$studlyModuleName}Controller::class, 'index']);
});
PHP;

        if (!$this->files->exists($routePath)) {
            $this->files->put($routePath, $routeContent);
            $this->line("创建路由文件: routes/web.php");
        }
    }
}
