import typer
import yaml as pyyaml
import os
from .config import CurdGenConfig
from .db import inspect_db
from .generator import Generator

app = typer.Typer()

def _load_config(config_path: str) -> CurdGenConfig:
    if not os.path.exists(config_path):
        typer.echo(f"错误: 找不到配置文件 {config_path}。")
        raise typer.Exit(code=1)
    with open(config_path, "r", encoding="utf-8") as f:
        config_data = pyyaml.safe_load(f)
    return CurdGenConfig(**config_data)

@app.command()
def crud(
    module: str = typer.Option(None, "--module", "-m", help="目标模块名"),
    config_path: str = typer.Option("curdezgen.yaml", help="配置文件路径"),
    overwrite: bool = typer.Option(False, "--overwrite", "-f", help="如果输出目录已存在，则覆盖它")
):
    """
    逆向工程：基于现有数据库表生成 CRUD 切片。
    """
    config = _load_config(config_path)
    
    typer.echo(f"正在检查数据库: {config.db.connection_url}")
    try:
        tables = inspect_db(config.db)
    except Exception as e:
        typer.echo(f"错误: 数据库连接失败: {str(e)}")
        raise typer.Exit(code=1)
    
    typer.echo(f"找到 {len(tables)} 张表。正在生成 CRUD 代码...")
    generator = Generator(config)
    generator.generate_crud(tables, module_name=module, overwrite=overwrite)
    typer.echo("CRUD 代码生成完成！")

@app.command()
def slice(
    name: str = typer.Argument(..., help="切片名称 (例如: send_otp)"),
    module: str = typer.Option(None, "--module", "-m", help="目标模块名"),
    method: str = typer.Option("POST", "--method", help="HTTP 方法 (GET, POST, etc.)"),
    config_path: str = typer.Option("curdezgen.yaml", help="配置文件路径")
):
    """
    正向工程：生成业务逻辑切片空壳。
    """
    config = _load_config(config_path)
    if not module:
        module = config.gen.default_module
        
    typer.echo(f"正在模块 {module} 中生成切片 {name}...")
    generator = Generator(config)
    generator.generate_blank_slice(module, name, method=method)
    typer.echo("切片生成完成！")

@app.command()
def init(
    config_path: str = typer.Option("curdezgen.yaml", help="配置文件路径"),
    force: bool = typer.Option(False, "--force", "-f", help="强制初始化，即使目录已存在")
):
    """
    初始化项目骨架 (core, shared, docker, etc.)。
    """
    config = _load_config(config_path)
    typer.echo(f"正在初始化项目结构: {config.gen.base_package}...")
    
    generator = Generator(config)
    generator.generate_skeleton(overwrite=force)
    
    typer.echo(f"项目 {config.gen.base_package} 基础结构初始化成功。")
    typer.echo(f"下一步: 修改 {config_path} 中的数据库配置，然后运行 'curdezgen crud'。")

@app.command()
def docker(
    config_path: str = typer.Option("curdezgen.yaml", help="配置文件路径")
):
    """
    生成 Docker 部署文件 (Dockerfile, docker-compose.yml, start_docker.sh/ps1)。
    """
    config = _load_config(config_path)
    typer.echo(f"正在生成 Docker 文件到 {config.gen.output_dir}/docker_file ...")
    
    generator = Generator(config)
    generator.generate_docker_files()
    
    typer.echo("Docker 文件生成完成！")

@app.command()
def gen(
    config_path: str = typer.Option("curdezgen.yaml", help="配置文件路径"),
    overwrite: bool = typer.Option(False, "--overwrite", "-f", help="如果输出目录已存在，则覆盖它")
):
    """
    (别名) 同 crud 命令。
    """
    crud(None, config_path, overwrite)

@app.command()
def yaml(
    output: str = typer.Option("curdezgen.yaml", help="配置文件保存路径"),
    force: bool = typer.Option(False, "--force", "-f", help="如果文件已存在，则强制覆盖")
):
    """
    第一步：生成默认配置文件模板。
    """
    if os.path.exists(output) and not force:
        typer.echo(f"错误: 文件 {output} 已存在。使用 -f 参数进行覆盖。")
        raise typer.Exit(code=1)

    default_config = {
        "db": {
            "type": "postgresql",
            "host": "localhost",
            "port": 5432,
            "user": "postgres",
            "password": "your_password",
            "name": "your_db_name",
            "schema_name": "public",
            "tables": None
        },
        "gen": {
            "output_dir": ".",
            "base_package": "app"
        }
    }

    with open(output, "w", encoding="utf-8") as f:
        pyyaml.dump(default_config, f, default_flow_style=False, sort_keys=False)
    
    typer.echo(f"已生成配置文件模板: {output}")
    typer.echo("下一步: 修改该文件中的数据库连接信息，然后运行 'curdezgen init'。")

if __name__ == "__main__":
    app()
