#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
模块名称：report_template.py
模块描述：功能测试报告模板配置 API 路由，提供模板的增删改查、设置默认等接口

作者：czj
创建日期：2026-08-13
最后修改：2026-08-13
"""

import json
import logging

from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession

from app.database import get_db
from app.models import ReportTemplate
from app.schemas.report_template import (
    ReportTemplateCreateRequest,
    ReportTemplateUpdateRequest,
    ReportTemplateListItem,
    ReportTemplateResponse,
)
from app.services.functional.config import get_default_config, merge_template_config

logger = logging.getLogger(__name__)

router = APIRouter(
    prefix="/templates",
    tags=["报告模板配置"],
)


async def _list_default_template(db: AsyncSession) -> ReportTemplate:
    """查找当前默认模板（不存在返回 None）"""
    result = await db.execute(
        select(ReportTemplate).where(ReportTemplate.is_default == True)  # noqa: E712
    )
    return result.scalar_one_or_none()


async def _clear_default_flag(db: AsyncSession) -> None:
    """清除所有模板的默认标记"""
    default = await _list_default_template(db)
    if default:
        default.is_default = False


async def _ensure_one_default(db: AsyncSession, current: ReportTemplate) -> None:
    """确保至少保留一个默认模板：如果没有任何默认模板，将当前模板设为默认"""
    result = await db.execute(select(ReportTemplate))
    total = len(result.scalars().all())
    if total == 1 and not current.is_default:
        current.is_default = True


def _validate_config(config: dict) -> dict:
    """校验模板配置：合并到默认配置，保证结构完整，移除无效键"""
    merged = merge_template_config(get_default_config(), config)
    return merged


# ==================== 模板列表 ====================


@router.get("", response_model=list[ReportTemplateListItem], summary="获取模板列表")
async def list_templates(db: AsyncSession = Depends(get_db)):
    """
    获取所有报告模板列表（不含 config 详情）

    Returns:
        List[ReportTemplateListItem]: 模板列表
    """
    result = await db.execute(select(ReportTemplate).order_by(ReportTemplate.updated_at.desc()))
    templates = result.scalars().all()
    return [t.to_list_item() for t in templates]


# ==================== 模板详情 ====================


@router.get("/{template_id}", response_model=ReportTemplateResponse, summary="获取模板详情")
async def get_template(template_id: int, db: AsyncSession = Depends(get_db)):
    """
    获取单个报告模板的完整配置

    Args:
        template_id: 模板ID

    Returns:
        ReportTemplateResponse: 模板完整信息（含config）
    """
    template = await db.get(ReportTemplate, template_id)
    if not template:
        raise HTTPException(status_code=404, detail=f"模板不存在: {template_id}")
    return template.to_dict()


# ==================== 创建模板 ====================


@router.post("", response_model=ReportTemplateResponse, summary="创建模板")
async def create_template(
    request: ReportTemplateCreateRequest,
    db: AsyncSession = Depends(get_db),
):
    """
    创建新的报告模板

    - config 会与默认配置合并，保证结构完整
    - 如果请求 is_default=True，则清除其他模板的默认标记
    - 当系统中还没有任何模板时，自动将新模板设为默认
    """
    # 检查名称是否重复
    result = await db.execute(select(ReportTemplate).where(ReportTemplate.name == request.name))
    if result.scalar_one_or_none():
        raise HTTPException(status_code=400, detail=f"模板名称已存在: {request.name}")

    # 合并配置，保证结构完整
    config = _validate_config(request.config)

    # 当系统还没有模板时，强制设为默认
    count_result = await db.execute(select(ReportTemplate.id))
    existing_count = len(count_result.scalars().all())

    is_default = request.is_default or existing_count == 0

    # 若设为默认，先清除其他默认标记
    if is_default:
        await _clear_default_flag(db)

    template = ReportTemplate(
        name=request.name,
        is_default=is_default,
        config=json.dumps(config, ensure_ascii=False),
        description=request.description or "",
    )
    db.add(template)
    await db.commit()
    await db.refresh(template)
    logger.info(f"创建报告模板: {template.name} (id={template.id}, is_default={template.is_default})")

    return template.to_dict()


# ==================== 更新模板 ====================


@router.put("/{template_id}", response_model=ReportTemplateResponse, summary="更新模板")
async def update_template(
    template_id: int,
    request: ReportTemplateUpdateRequest,
    db: AsyncSession = Depends(get_db),
):
    """
    更新报告模板

    - 可单独更新 name / config / is_default
    - 更新后的 config 会与默认配置合并
    - 若请求 is_default=True，则清除其他模板的默认标记
    """
    template = await db.get(ReportTemplate, template_id)
    if not template:
        raise HTTPException(status_code=404, detail=f"模板不存在: {template_id}")

    # 名称重复校验（排除自身）
    if request.name is not None and request.name != template.name:
        result = await db.execute(
            select(ReportTemplate).where(ReportTemplate.name == request.name)
        )
        duplicate = result.scalar_one_or_none()
        if duplicate and duplicate.id != template_id:
            raise HTTPException(status_code=400, detail=f"模板名称已存在: {request.name}")

    if request.name is not None:
        template.name = request.name

    if request.description is not None:
        template.description = request.description

    if request.config is not None:
        template.config = json.dumps(_validate_config(request.config), ensure_ascii=False)

    if request.is_default:
        await _clear_default_flag(db)
        template.is_default = True

    await db.commit()

    # 无论如何保留一个默认模板
    await _ensure_one_default(db, template)
    await db.commit()
    await db.refresh(template)
    logger.info(f"更新报告模板: {template.name} (id={template.id})")

    return template.to_dict()


# ==================== 设为默认 ====================


@router.put("/{template_id}/default", response_model=ReportTemplateResponse, summary="设为默认模板")
async def set_default_template(template_id: int, db: AsyncSession = Depends(get_db)):
    """
    将指定模板设为默认模板（全局唯一）
    """
    template = await db.get(ReportTemplate, template_id)
    if not template:
        raise HTTPException(status_code=404, detail=f"模板不存在: {template_id}")

    if not template.is_default:
        await _clear_default_flag(db)
        template.is_default = True
        await db.commit()
        await db.refresh(template)
        logger.info(f"设为默认模板: {template.name} (id={template.id})")

    return template.to_dict()


# ==================== 删除模板 ====================


@router.delete("/{template_id}", summary="删除模板")
async def delete_template(template_id: int, db: AsyncSession = Depends(get_db)):
    """
    删除报告模板

    - 不允许删除最后一个模板（至少保留一个）
    """
    template = await db.get(ReportTemplate, template_id)
    if not template:
        raise HTTPException(status_code=404, detail=f"模板不存在: {template_id}")

    # 检查剩余模板数量
    result = await db.execute(select(ReportTemplate.id))
    total = len(result.scalars().all())
    if total <= 1:
        raise HTTPException(status_code=400, detail="至少需要保留一个模板，不能删除最后一个")

    was_default = template.is_default
    await db.delete(template)
    await db.commit()
    logger.info(f"删除报告模板: {template.name} (id={template_id})")

    # 如果删除的是默认模板，把剩余的第一个设为默认
    if was_default:
        remaining = await db.execute(select(ReportTemplate).order_by(ReportTemplate.updated_at.desc()))
        first = remaining.scalars().first()
        if first:
            first.is_default = True
            await db.commit()
            logger.info(f"删除默认模板后，自动将 {first.name} (id={first.id}) 设为默认")

    return {"success": True, "message": "模板已删除"}


# ==================== 复制模板 ====================


@router.post("/{template_id}/duplicate", response_model=ReportTemplateResponse, summary="复制模板")
async def duplicate_template(template_id: int, db: AsyncSession = Depends(get_db)):
    """
    复制报告模板

    复制后的模板：
    - 名称自动加"副本"后缀（已存在同名则追加序号）
    - config 与 description 完整继承
    - is_default 强制设为 False
    """
    template = await db.get(ReportTemplate, template_id)
    if not template:
        raise HTTPException(status_code=404, detail=f"模板不存在: {template_id}")

    # 生成不重复的名称
    base_name = template.name
    new_name = f"{base_name}_副本"
    num = 2
    while True:
        result = await db.execute(select(ReportTemplate).where(ReportTemplate.name == new_name))
        if not result.scalar_one_or_none():
            break
        new_name = f"{base_name}_副本{num}"
        num += 1

    new_template = ReportTemplate(
        name=new_name,
        is_default=False,
        config=template.config,
        description=template.description or "",
    )
    db.add(new_template)
    await db.commit()
    await db.refresh(new_template)
    logger.info(f"复制报告模板: {template.name} → {new_template.name} (id={new_template.id})")
    return new_template.to_dict()