# _*_ coding : UTF-8 _*_
# @Time : 2025/02/28 17:28
# @UpdateTime : 2025/02/28 17:28
# @Author : sonder
# @File : generate.py
# @Software : PyCharm
# @Comment : 本程序
import uuid
from datetime import datetime
from typing import Optional

from fastapi import APIRouter, Path, Query, Depends, Request
from fastapi.responses import JSONResponse
from jinja2 import Environment, FileSystemLoader
from tortoise import Tortoise

from annotation.auth import Auth
from annotation.log import Log
from config.constant import MYSQL_TO_PYTHON_TYPE, BusinessType
from controller.login import LoginController
from models.generate import GenerateInfo, GenerateColumn
from schemas.common import BaseResponse, DeleteListParams
from schemas.generate import GetTablesListResponse, AddGenerateInfoParams, UpdateGenerateInfoParams, \
    GetGenerateInfoResponse, GetGenerateInfoListResponse
from utils.common import bytes2human
from utils.generate import Generate
from utils.response import Response

generateAPI = APIRouter(
    prefix="/generate",
    dependencies=[Depends(LoginController.get_current_user)]
)


@generateAPI.get("/tables", response_class=JSONResponse, response_model=GetTablesListResponse,
                 summary="获取数据库中的所有表信息")
@Log(title="获取数据库中的所有表信息", business_type=BusinessType.SELECT)
@Auth(permission_list=["generate:btn:tables"])
async def get_database_tables(request: Request):
    """
    获取当前数据库中的所有表信息，包括：
    - 表名
    - 表注释
    - 记录行数
    - 数据大小
    - 索引大小
    - 创建时间
    - 最后更新时间（如果支持）
    """
    sql = """SELECT TABLE_NAME,TABLE_COMMENT,TABLE_ROWS,DATA_LENGTH,INDEX_LENGTH,CREATE_TIME,UPDATE_TIME FROM information_schema.tables WHERE table_schema = DATABASE();"""
    result = await Tortoise.get_connection("default").execute_query_dict(sql)
    # 将结果中的键转换为小写
    formatted_result = [{k.lower(): v for k, v in row.items()} for row in result]
    for row in formatted_result:
        for key, value in row.items():
            if key == "data_length" or key == "index_length":
                row[key] = bytes2human(value)
    return Response.success(data={
        "page": 1,
        "total": len(formatted_result),
        "pageSize": 99999,
        "result": formatted_result
    })


@generateAPI.post("/add", response_class=JSONResponse, response_model=BaseResponse, summary="添加生成表信息")
@Log(title="添加生成表信息", business_type=BusinessType.INSERT)
@Auth(permission_list=["generate:btn:add"])
async def add_generate_info(request: Request, params: AddGenerateInfoParams):
    if await GenerateInfo.get_or_none(table_name=params.table_name, del_flag=1):
        return Response.error(msg="该表信息已存在！")
    gen = await GenerateInfo.create(
        author=params.author,
        class_name=params.class_name,
        table_comment=params.table_comment,
        table_name=params.table_name,
        prefix=params.prefix,
        remark=params.remark,
        permission_id=params.permission_id,
        description=params.description
    )
    if gen:
        sql = """SELECT * FROM information_schema.columns  WHERE table_schema = DATABASE() AND table_name = %s;"""
        result = await Tortoise.get_connection("default").execute_query_dict(sql, [params.table_name])
        # 转换为小写键名
        formatted_result = [{k.lower(): v for k, v in row.items()} for row in result]
        formatted_result.sort(key=lambda x: x['ordinal_position'])
        common_column = ["id", "del_flag", "create_by", "update_by", "create_time", "update_time"]
        common_set = {
            "id": {
                "is_insert": False,
                "is_edit": False,
                "is_list": True,
                "is_query": False,
                "is_required": False,
                "is_hide": True,
            },
            "del_flag": {
                "is_insert": False,
                "is_edit": False,
                "is_list": False,
                "is_query": False,
                "is_required": False,
                "is_hide": True,
            },
            "create_by": {
                "is_insert": False,
                "is_edit": False,
                "is_list": False,
                "is_query": False,
                "is_required": False,
                "is_hide": True,
            },
            "update_by": {
                "is_insert": False,
                "is_edit": False,
                "is_list": False,
                "is_query": False,
                "is_required": False,
                "is_hide": True,
            },
            "create_time": {
                "is_insert": False,
                "is_edit": False,
                "is_list": True,
                "is_query": False,
                "is_required": False,
                "is_hide": False,
            },
            "update_time": {
                "is_insert": False,
                "is_edit": False,
                "is_list": True,
                "is_query": False,
                "is_required": False,
                "is_hide": False,
            }
        }
        for column in formatted_result:
            if await GenerateColumn.get_or_none(table_id=gen.id, column_name=column["column_name"], del_flag=1):
                continue
            is_insert = True
            is_edit = True
            is_list = True
            is_query = True
            is_required = True
            is_hide = False
            if column["column_name"] in common_column:
                is_insert = common_set[column["column_name"]]["is_insert"]
                is_edit = common_set[column["column_name"]]["is_edit"]
                is_list = common_set[column["column_name"]]["is_list"]
                is_query = common_set[column["column_name"]]["is_query"]
                is_required = common_set[column["column_name"]]["is_required"]
                is_hide = common_set[column["column_name"]]["is_hide"]
            await GenerateColumn.create(
                table=gen,
                index=column["ordinal_position"],
                column_name=column["column_name"],
                column_comment=column["column_comment"],
                column_type=column["column_type"],
                python_type=MYSQL_TO_PYTHON_TYPE.get(column["column_type"]) if MYSQL_TO_PYTHON_TYPE.get(
                    column["column_type"]) else MYSQL_TO_PYTHON_TYPE.get(column["data_type"], "str"),
                python_name=column["column_name"].lower(),
                is_insert=is_insert,
                is_edit=is_edit,
                is_list=is_list,
                is_query=is_query,
                is_required=is_required,
                query_way="__icontains",
                show_type="input",
                is_hide=is_hide,
            )
        return Response.success(msg="添加成功！")
    return Response.error(msg="添加失败！")


@generateAPI.delete("/delete/{id}", response_class=JSONResponse, response_model=BaseResponse, summary="删除生成表信息")
@generateAPI.post("/delete/{id}", response_class=JSONResponse, response_model=BaseResponse, summary="删除生成表信息")
@Log(title="删除生成表信息", business_type=BusinessType.DELETE)
@Auth(permission_list=["generate:btn:delete"])
async def delete_generate_info(request: Request, id: str = Path(description="生成表信息ID")):
    if table := await GenerateInfo.get_or_none(id=id, del_flag=1):
        table.del_flag = 0
        await GenerateColumn.filter(table_id=table.id, del_flag=1).update(del_flag=0)
        await table.save()
        return Response.success(msg="删除成功！")
    return Response.error(msg="该生成表信息不存在！")


@generateAPI.delete("/deleteList", response_class=JSONResponse, response_model=BaseResponse,
                    summary="批量删除生成表信息")
@generateAPI.post("/deleteList", response_class=JSONResponse, response_model=BaseResponse, summary="批量删除生成表信息")
@Log(title="批量删除生成表信息", business_type=BusinessType.DELETE)
@Auth(permission_list=["generate:btn:delete"])
async def delete_generate_info_list(request: Request, params: DeleteListParams):
    for id in set(params.ids):
        if table := await GenerateInfo.get_or_none(id=id, del_flag=1):
            table.del_flag = 0
            await GenerateColumn.filter(table_id=table.id, del_flag=1).update(del_flag=0)
            await table.save()
    return Response.success(msg="删除成功！")


@generateAPI.put("/update/{id}", response_class=JSONResponse, response_model=BaseResponse, summary="更新生成表信息")
@generateAPI.post("/update/{id}", response_class=JSONResponse, response_model=BaseResponse, summary="更新生成表信息")
@Log(title="更新生成表信息", business_type=BusinessType.UPDATE)
@Auth(permission_list=["generate:btn:update"])
async def update_generate_info(
        request: Request,
        params: AddGenerateInfoParams,
        id: str = Path(description="生成表信息ID")
):
    if table := await GenerateInfo.get_or_none(id=id, del_flag=1):
        table.author = params.info.author
        table.class_name = params.info.class_name
        table.permission_id = params.info.permission_id
        table.prefix = params.info.prefix
        table.remark = params.info.remark
        table.table_comment = params.info.table_comment
        table.table_name = params.info.table_name
        table.description = params.info.description
        await table.save()

        return Response.success(msg="更新成功！")
    return Response.error(msg="该生成表信息不存在！")


@generateAPI.get("/info/{id}", response_class=JSONResponse, response_model=GetGenerateInfoResponse,
                 summary="获取生成表信息")
@Log(title="获取生成表信息", business_type=BusinessType.SELECT)
@Auth(permission_list=["generate:btn:info"])
async def get_generate_info(request: Request, id: str = Path(description="生成表信息ID")):
    if table := await GenerateInfo.get_or_none(id=id, del_flag=1):
        table = {
            "id": table.id,
            "author": table.author,
            "class_name": table.class_name,
            "permission_id": table.permission_id,
            "prefix": table.prefix,
            "remark": table.remark,
            "table_comment": table.table_comment,
            "table_name": table.table_name,
            "description": table.description,
            "create_time": table.create_time,
            "update_time": table.update_time,
        }
        columns = await GenerateColumn.filter(table_id=table["id"], del_flag=1).order_by("index").values(
            id="id",
            table_id="table__id",
            table_name="table__table_name",
            index="index",
            column_comment="column_comment",
            column_name="column_name",
            column_type="column_type",
            python_name="python_name",
            python_type="python_type",
            query_way="query_way",
            show_type="show_type",
            is_insert="is_insert",
            is_edit="is_edit",
            is_list="is_list",
            is_query="is_query",
            is_required="is_required",
            is_hide="is_hide",
            create_time="create_time",
            update_time="update_time",
        )
        table["columns"] = columns
        return Response.success(data=table)
    return Response.error(msg="该生成表信息不存在！")


@generateAPI.put("/updateColumns/{id}", response_class=JSONResponse, response_model=BaseResponse,
                 summary="更新生成表列信息")
@generateAPI.post("/updateColumns/{id}", response_class=JSONResponse, response_model=BaseResponse,
                  summary="更新生成表列信息")
@Log(title="更新生成表列信息", business_type=BusinessType.UPDATE)
@Auth(permission_list=["generate:btn:updateColumns"])
async def update_generate_info_columns(
        request: Request,
        params: UpdateGenerateInfoParams,
        id: str = Path(description="生成表信息ID")
):
    if table := await GenerateInfo.get_or_none(id=id, del_flag=1):
        for column in params.columns:
            if gen_column := await GenerateColumn.get_or_none(id=column.id, table_id=table.id, del_flag=1):
                gen_column.column_comment = column.column_comment
                gen_column.column_name = column.column_name
                gen_column.column_type = column.column_type
                gen_column.python_name = column.python_name
                gen_column.python_type = column.python_type
                gen_column.query_way = column.query_way
                gen_column.show_type = column.show_type
                gen_column.is_insert = column.is_insert
                gen_column.is_edit = column.is_edit
                gen_column.is_list = column.is_list
                gen_column.is_query = column.is_query
                gen_column.is_required = column.is_required
                gen_column.is_hide = column.is_hide
                await gen_column.save()
        return Response.success(msg="更新成功！")
    return Response.error(msg="该生成表信息不存在！")


@generateAPI.get("/list", response_class=JSONResponse, response_model=GetGenerateInfoListResponse,
                 summary="查询生成表信息列表")
@Log(title="查询生成表信息列表", business_type=BusinessType.SELECT)
@Auth(permission_list=["generate:btn:list"])
async def get_generate_info_list(
        request: Request,
        page: int = Query(default=1, description="页码"),
        pageSize: int = Query(default=10, description="每页数量"),
        table_comment: Optional[str] = Query(default=None, description="表注释"),
        permission_id: Optional[str] = Query(default=None, description="权限ID"),
):
    filterArgs = {
        f'{k}__contains': v for k, v in {
            'table_comment': table_comment,
            'permission_id': permission_id
        }.items() if v
    }
    result = await GenerateInfo.filter(**filterArgs, del_flag=1).order_by("-create_time").offset(
        (page - 1) * pageSize).limit(
        pageSize).values(
        id="id",
        author="author",
        class_name="class_name",
        permission_id="permission_id",
        prefix="prefix",
        remark="remark",
        table_comment="table_comment",
        table_name="table_name",
        description="description",
        create_time="create_time",
        update_time="update_time",
    )
    for item in result:
        columns = await GenerateColumn.filter(table_id=item["id"], del_flag=1).order_by("index").values(
            id="id",
            table_id="table__id",
            table_name="table__table_name",
            index="index",
            column_comment="column_comment",
            column_name="column_name",
            column_type="column_type",
            python_name="python_name",
            python_type="python_type",
            query_way="query_way",
            show_type="show_type",
            is_insert="is_insert",
            is_edit="is_edit",
            is_list="is_list",
            is_query="is_query",
            is_required="is_required",
            is_hide="is_hide",
            create_time="create_time",
            update_time="update_time",
        )
        item["columns"] = columns
    return Response.success(data={
        "result": result,
        "total": await GenerateInfo.filter(**filterArgs, del_flag=1).count(),
        "page": page,
        "pageSize": pageSize,
    })


@generateAPI.get("/code/{id}", response_class=JSONResponse, response_model=BaseResponse, summary="生成代码")
@Log(title="生成代码", business_type=BusinessType.GENCODE)
@Auth(permission_list=["generate:btn:code"])
async def generate_code(
        request: Request,
        id: str = Path(description="生成表信息ID")
):
    if table := await GenerateInfo.get_or_none(id=id, del_flag=1):
        info = {
            "author": table.author,
            "class_name": table.class_name,
            "permission_id": table.permission_id,
            "prefix": table.prefix,
            "remark": table.remark,
            "table_comment": table.table_comment,
            "table_name": table.table_name,
            "description": table.description,
        }
        columns = await GenerateColumn.filter(table_id=table.id, del_flag=1).order_by("index").values(
            id="id",
            table_id="table__id",
            table_name="table__table_name",
            index="index",
            column_comment="column_comment",
            column_name="column_name",
            column_type="column_type",
            python_name="python_name",
            python_type="python_type",
            query_way="query_way",
            show_type="show_type",
            is_insert="is_insert",
            is_edit="is_edit",
            is_list="is_list",
            is_query="is_query",
            is_required="is_required",
            is_hide="is_hide",
            create_time="create_time",
            update_time="update_time",
        )

        def generate_uuid():
            return str(uuid.uuid4())

        def current_time():
            return datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")

        comment_env = Environment(loader=FileSystemLoader('templates'))
        comment_env.globals["uuid4"] = generate_uuid  # 注册到 Jinja2
        comment_env.globals["now"] = current_time
        data = Generate.prepare_template_data(info, columns)
        model_template = comment_env.get_template('python/model.py.jinja')
        model_code = model_template.render(data)
        schemas_template = comment_env.get_template('python/schemas.py.jinja')
        schemas_code = schemas_template.render(data)
        api_py_template = comment_env.get_template('python/api.py.jinja')
        api_py_code = api_py_template.render(data)
        type_template = comment_env.get_template('typescript/type.d.ts.jinja')
        type_code = type_template.render(data)
        api_ts_template = comment_env.get_template('typescript/api.ts.jinja')
        api_ts_code = api_ts_template.render(data)
        hook_template = comment_env.get_template('typescript/hook.tsx.jinja')
        hook_code = hook_template.render(data)
        vue_env = Environment(
            loader=FileSystemLoader('templates/vue'),
            block_start_string="[%",  # 替换 Jinja2 代码块的起始标记
            block_end_string="%]",  # 替换 Jinja2 代码块的结束标记
            variable_start_string="[[",
            variable_end_string="]]",
            comment_start_string="[#",
            comment_end_string="#]"
        )
        index_template = vue_env.get_template('index.vue.jinja')
        index_code = index_template.render(data)
        form_template = vue_env.get_template('form.vue.jinja')
        form_code = form_template.render(data)
        sql_template = comment_env.get_template('sql.jinja')
        sql_code = sql_template.render(data)
        data = {
            "backend": [
                {
                    "label": f"/models/{info['class_name'].lower()}.py",
                    "value": model_code,
                    "type": "python",
                    "path": f"/python/models/{info['class_name'].lower()}.py"
                },
                {
                    "label": f"/schemas/{info['class_name'].lower()}.py",
                    "value": schemas_code,
                    "type": "python",
                    "path": f"/python/schemas/{info['class_name'].lower()}.py"
                },
                {
                    "label": f"/api/{info['class_name'].lower()}.py",
                    "value": api_py_code,
                    "type": "python",
                    "path": f"/python/api/{info['class_name'].lower()}.py"
                },
            ],
            "frontend": [
                {
                    "label": f"/types/{info['class_name'].lower()}.d.ts",
                    "value": type_code,
                    "type": "typescript",
                    "path": f"/types/{info['class_name'].lower()}.d.ts"
                },
                {
                    "label": f"/api/{info['class_name'].lower()}.ts",
                    "value": api_ts_code,
                    "type": "typescript",
                    "path": f"/api/{info['class_name'].lower()}.ts"
                },
                {
                    "label": f"/{info['class_name'].lower()}/utils/hook.tsx",
                    "value": hook_code,
                    "type": "typescript",
                    "path": f"/{info['class_name'].lower()}/utils/hook.tsx"
                },
                {
                    "label": f"/{info['class_name'].lower()}/index.vue",
                    "value": index_code,
                    "type": "vue",
                    "path": f"/{info['class_name'].lower()}/index.vue"
                },
                {
                    "label": f"/{info['class_name'].lower()}/components/form.vue",
                    "value": form_code,
                    "type": "vue",
                    "path": f"/{info['class_name'].lower()}/components/form.vue"
                },
            ],
            "sql": [
                {
                    "label": f"{info['table_name']}.sql",
                    "value": sql_code,
                    "type": "sql",
                    "path": f"{info['table_name']}.sql"
                }
            ]
        }
        return Response.success(data=data)
    return Response.error(msg="生成失败！")
