"""邮件测试 / 日志 / 模板 API"""
from datetime import datetime

from fastapi import APIRouter, Depends, HTTPException, Query
from pydantic import BaseModel, EmailStr
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, func

from app.api.deps import get_db, get_admin_user
from app.core.models.user import User
from app.core.models.tenant_settings import TenantSettings
from app.core.models.email_log import EmailLog
from app.core.models.email_template import EmailTemplate
from app.services.email import (
    build_smtp_config, send_test_email, SmtpSendError,
    TEMPLATE_META, _get_tenant_default_locale,
)

router = APIRouter(prefix="/admin/email", tags=["邮件管理"])

_VALID_KEYS = set(TEMPLATE_META.keys())


# ── Schemas ────────────────────────────────────────────────────────────────

class TestEmailIn(BaseModel):
    to_email: EmailStr


class TestEmailOut(BaseModel):
    message: str
    smtp_message_id: str | None = None


class EmailLogOut(BaseModel):
    id: int
    to_email: str
    subject: str
    status: str
    smtp_host: str | None = None
    smtp_port: int | None = None
    error_type: str | None = None
    smtp_code: int | None = None
    detail: str | None = None
    created_at: datetime

    model_config = {"from_attributes": True}


class EmailLogListOut(BaseModel):
    items: list[EmailLogOut]
    total: int


class TemplateIn(BaseModel):
    subject: str
    body: str
    is_enabled: int = 1
    notify_list_enabled: int = 0
    attach_invoice: int = 0
    # language is passed as a query param to GET/PUT, not in the request body


class TemplateOut(BaseModel):
    key: str
    name: str
    description: str
    subject: str
    body: str
    is_enabled: int
    notify_list_enabled: int = 0
    attach_invoice: int = 0
    is_custom: bool
    language: str = "zh"
    available_languages: list[str] = []
    variables: list[dict]


# ── Helpers ────────────────────────────────────────────────────────────────

async def _get_settings(tenant_id: int, db: AsyncSession) -> TenantSettings | None:
    result = await db.execute(
        select(TenantSettings).where(TenantSettings.tenant_id == tenant_id)
    )
    return result.scalar_one_or_none()


async def _get_template(tenant_id: int, key: str, db: AsyncSession, language: str = "zh") -> EmailTemplate | None:
    r = await db.execute(
        select(EmailTemplate).where(
            EmailTemplate.tenant_id == tenant_id,
            EmailTemplate.template_key == key,
            EmailTemplate.language == language,
        )
    )
    return r.scalar_one_or_none()


# ── Routes ─────────────────────────────────────────────────────────────────

@router.post("/test", response_model=TestEmailOut, summary="发送测试邮件")
async def test_email(
    body: TestEmailIn,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_admin_user),
):
    s = await _get_settings(current_user.tenant_id, db)
    smtp_cfg = build_smtp_config(s)

    log = EmailLog(
        tenant_id=current_user.tenant_id,
        to_email=str(body.to_email),
        subject="测试邮件",
        smtp_host=smtp_cfg.get("host") or None,
        smtp_port=smtp_cfg.get("port") or None,
    )

    try:
        msg_id = await send_test_email(str(body.to_email), smtp_cfg)
        log.status = "sent"
        db.add(log)
        await db.commit()
        return TestEmailOut(
            message=f"测试邮件已成功发送至 {body.to_email}",
            smtp_message_id=msg_id or None,
        )
    except SmtpSendError as exc:
        log.status     = "failed"
        log.error_type = exc.error_type
        log.smtp_code  = exc.smtp_code
        log.detail     = exc.detail
        db.add(log)
        await db.commit()
        raise HTTPException(
            status_code=400,
            detail={
                "detail":     exc.detail,
                "error_type": exc.error_type,
                "smtp_code":  exc.smtp_code,
            },
        )


@router.get("/logs", response_model=EmailLogListOut, summary="邮件发送日志")
async def list_email_logs(
    page:      int = Query(1, ge=1),
    page_size: int = Query(20, ge=1, le=100),
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_admin_user),
):
    base = select(EmailLog).where(EmailLog.tenant_id == current_user.tenant_id)
    total = (await db.execute(select(func.count()).select_from(base.subquery()))).scalar_one()
    items = (
        await db.execute(
            base.order_by(EmailLog.created_at.desc())
                .offset((page - 1) * page_size)
                .limit(page_size)
        )
    ).scalars().all()
    return EmailLogListOut(items=list(items), total=total)


@router.get("/templates", response_model=list[TemplateOut], summary="获取所有邮件模板")
async def list_templates(
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_admin_user),
):
    default_locale = await _get_tenant_default_locale(db, current_user.tenant_id)
    # Get all custom templates for this tenant in the tenant's default language
    result = await db.execute(
        select(EmailTemplate).where(
            EmailTemplate.tenant_id == current_user.tenant_id,
            EmailTemplate.language == default_locale,
        )
    )
    db_map = {tpl.template_key: tpl for tpl in result.scalars().all()}

    # Get all customized (template_key, language) pairs for available_languages
    custom_result = await db.execute(
        select(EmailTemplate.template_key, EmailTemplate.language)
        .where(EmailTemplate.tenant_id == current_user.tenant_id)
    )
    custom_map: dict[str, list[str]] = {}
    for row in custom_result.fetchall():
        custom_map.setdefault(row.template_key, []).append(row.language)

    out = []
    for key, meta in TEMPLATE_META.items():
        tpl = db_map.get(key)
        out.append(TemplateOut(
            key=key,
            name=meta["name"],
            description=meta["description"],
            subject=tpl.subject if tpl else meta["default_subject"],
            body=tpl.body if tpl else meta["default_body"],
            is_enabled=tpl.is_enabled if tpl else 1,
            notify_list_enabled=tpl.notify_list_enabled if tpl else meta.get("notify_list_enabled", 0),
            attach_invoice=tpl.attach_invoice if tpl else meta.get("attach_invoice", 0),
            is_custom=tpl is not None,
            language=default_locale,
            available_languages=custom_map.get(key, []),
            variables=meta["variables"],
        ))
    return out


@router.get("/templates/{key}", response_model=TemplateOut, summary="获取单个邮件模板")
async def get_template(
    key: str,
    language: str = Query("zh"),
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_admin_user),
):
    if key not in _VALID_KEYS:
        raise HTTPException(status_code=404)
    result = await db.execute(
        select(EmailTemplate).where(
            EmailTemplate.tenant_id == current_user.tenant_id,
            EmailTemplate.template_key == key,
            EmailTemplate.language == language,
        )
    )
    tpl = result.scalar_one_or_none()
    meta = TEMPLATE_META[key]
    if not tpl:
        return TemplateOut(
            key=key, name=meta["name"], description=meta["description"],
            subject=meta["default_subject"], body=meta["default_body"],
            is_enabled=1, notify_list_enabled=meta.get("notify_list_enabled", 0),
            attach_invoice=meta.get("attach_invoice", 0), is_custom=False, language=language,
            available_languages=[], variables=meta["variables"],
        )
    return TemplateOut(
        key=key, name=meta["name"], description=meta["description"],
        subject=tpl.subject, body=tpl.body,
        is_enabled=tpl.is_enabled, notify_list_enabled=tpl.notify_list_enabled,
        attach_invoice=tpl.attach_invoice, is_custom=True, language=language,
        available_languages=[language], variables=meta["variables"],
    )


@router.put("/templates/{key}", response_model=TemplateOut, summary="保存邮件模板")
async def upsert_template(
    key: str,
    body: TemplateIn,
    language: str = Query("zh"),
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_admin_user),
):
    if key not in _VALID_KEYS:
        raise HTTPException(status_code=404, detail=f"未知模板 key：{key}")

    result = await db.execute(
        select(EmailTemplate).where(
            EmailTemplate.tenant_id == current_user.tenant_id,
            EmailTemplate.template_key == key,
            EmailTemplate.language == language,
        )
    )
    tpl = result.scalar_one_or_none()
    if tpl:
        tpl.subject = body.subject
        tpl.body = body.body
        tpl.is_enabled = body.is_enabled
        tpl.notify_list_enabled = body.notify_list_enabled
        tpl.attach_invoice = body.attach_invoice
    else:
        tpl = EmailTemplate(
            tenant_id=current_user.tenant_id,
            template_key=key,
            language=language,
            subject=body.subject,
            body=body.body,
            is_enabled=body.is_enabled,
            notify_list_enabled=body.notify_list_enabled,
            attach_invoice=body.attach_invoice,
        )
        db.add(tpl)
    await db.commit()
    await db.refresh(tpl)
    meta = TEMPLATE_META[key]
    return TemplateOut(
        key=key, name=meta["name"], description=meta["description"],
        subject=tpl.subject, body=tpl.body,
        is_enabled=tpl.is_enabled, notify_list_enabled=tpl.notify_list_enabled,
        attach_invoice=tpl.attach_invoice, is_custom=True, language=language,
        available_languages=[language], variables=meta["variables"],
    )


@router.delete("/templates/{key}", summary="重置模板为内置默认")
async def reset_template(
    key: str,
    language: str = Query("zh"),
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_admin_user),
):
    if key not in _VALID_KEYS:
        raise HTTPException(status_code=404, detail=f"未知模板 key：{key}")
    tpl = await _get_template(current_user.tenant_id, key, db, language)
    if tpl:
        await db.delete(tpl)
        await db.commit()
    return {"message": "已重置为默认模板"}
