<?php

namespace Kylin\Modules\Console\Commands;

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

/**
 * 创建模块迁移命令
 *
 * 用于为指定模块创建新的迁移文件
 */
class ModuleMakeMigrationCommand extends Command
{
    /**
     * 命令名称和签名
     *
     * @var string
     * 
     * 命令参数说明：
     * 1. {module} - 模块名称（必填）
     *    - 数据类型：字符串
     *    - 用途：指定迁移文件所属的模块名称
     *    - 示例：php artisan module:make-migration game create_users_table
     * 
     * 2. {name} - 迁移名称（必填）
     *    - 数据类型：字符串
     *    - 用途：指定要创建的迁移文件名称
     *    - 示例：php artisan module:make-migration game create_users_table
     * 
     * 命令选项说明：
     * 1. {--c|create=} - 要创建的表
     *    - 简写：-c
     *    - 完整形式：--create
     *    - 数据类型：字符串
     *    - 用途：指定要创建的数据库表名称
     *    - 示例：php artisan module:make-migration game create_users_table --create=users
     * 
     * 2. {--t|table=} - 要迁移的表
     *    - 简写：-t
     *    - 完整形式：--table
     *    - 数据类型：字符串
     *    - 用途：指定要进行迁移的数据库表名称
     *    - 示例：php artisan module:make-migration game add_email_to_users_table --table=users
     */
    protected $signature = 'module:make-migration {module : 模块名称} {name : 迁移名称} {--c|create= : 要创建的表} {--t|table= : 要迁移的表}';

    /**
     * 命令描述
     *
     * @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');
        $migrationName = (string) $this->argument('name');
        $create = $this->option('create');
        $table = $this->option('table');

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

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

        $migrationPath = $this->getMigrationPath($module, $migrationName);
        $migrationClass = $this->getMigrationClass($migrationName);

        if ($this->files->exists($migrationPath)) {
            $this->error("迁移 [{$migrationClass}] 在模块 [{$moduleName}] 中已存在。");
            return 1;
        }

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

        $stub = $this->getStub($create, $table);
        $content = $this->replaceStubVariables($stub, $migrationClass, $create ?: $table);

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

        $this->info("迁移 [{$migrationClass}] 在模块 [{$moduleName}] 中创建成功！");
        $this->info("迁移路径: {$migrationPath}");

        return 0;
    }

    /**
     * 获取迁移路径
     *
     * @param  \Kylin\Modules\Module  $module  模块实例
     * @param  string  $migrationName  迁移名称
     * @return string
     */
    protected function getMigrationPath($module, string $migrationName): string
    {
        $timestamp = date('Y_m_d_His');
        return $module->getPath('database/migrations/' . $timestamp . '_' . $migrationName . '.php');
    }

    /**
     * 获取迁移类名
     *
     * @param  string  $migrationName  迁移名称
     * @return string
     */
    protected function getMigrationClass(string $migrationName): string
    {
        return Str::studly($migrationName);
    }

    /**
     * 获取模板文件
     *
     * @param  string|null  $create  要创建的表
     * @param  string|null  $table  要迁移的表
     * @return string
     */
    protected function getStub(mixed $create, mixed $table): string
    {
        if ($create) {
            $stubPath = __DIR__ . '/../../../stubs/migration.create.stub';
            return $this->files->get($stubPath);
        }

        if ($table) {
            $stubPath = __DIR__ . '/../../../stubs/migration.update.stub';
            return $this->files->get($stubPath);
        }

        $stubPath = __DIR__ . '/../../../stubs/migration.plain.stub';
        return $this->files->get($stubPath);
    }

    /**
     * 替换模板变量
     *
     * @param  string  $stub  模板内容
     * @param  string  $class  类名
     * @param  string|null  $table  表名
     * @return string
     */
    protected function replaceStubVariables(string $stub, string $class, mixed $table): string
    {
        $stub = str_replace('{{ class }}', $class, $stub);
        $stub = str_replace('{{ table }}', $table, $stub);

        return $stub;
    }
}