import re as _re
from fastapi import APIRouter, Depends, HTTPException, Query, status
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, func
from typing import Optional
from datetime import datetime

from app.api.deps import get_db, get_admin_user
from app.core.cache import cache_delete
from app.core.models.category import Category
from app.core.models.product import Product
from app.core.models.user import User
from app.core.models.tenant_settings import TenantSettings
from app.core.ai_utils import call_ai, resolve_ai_extra
from app.core.services.ai_quota import consume_ai_quota
from app.plugins.pos_sync.revision import bump_revision
from pydantic import BaseModel
import json as _json

router = APIRouter(prefix="/categories", tags=["分类管理"])


def _strip_html(text: str, max_chars: int = 400) -> str:
    """Remove HTML tags and truncate to max_chars plain-text characters."""
    if not text:
        return ""
    text = _re.sub(r"<(style|script)[^>]*>.*?</(style|script)>", " ", text, flags=_re.DOTALL | _re.IGNORECASE)
    text = _re.sub(r"<[^>]+>", " ", text)
    for esc, char in [("&nbsp;", " "), ("&amp;", "&"), ("&lt;", "<"), ("&gt;", ">"), ("&quot;", '"'), ("&#39;", "'")]:
        text = text.replace(esc, char)
    text = " ".join(text.split())
    if len(text) > max_chars:
        return text[:max_chars] + "…"
    return text


class CategoryOut(BaseModel):
    id: int
    parent_id: int | None
    name: str
    slug: str
    description: str | None
    image_url: str | None
    meta_title: str | None
    meta_description: str | None
    seo_keywords: str | None
    name_en: str | None = None
    description_en: str | None = None
    meta_title_en: str | None = None
    meta_description_en: str | None = None
    seo_keywords_en: str | None = None
    sort_order: int = 0
    is_active: bool = True
    is_nav_visible: bool = True
    created_at: Optional[datetime] = None
    updated_at: Optional[datetime] = None
    product_count: int = 0

    model_config = {"from_attributes": True}


class CategoryCreate(BaseModel):
    name: str
    slug: str
    parent_id: int | None = None
    description: str | None = None
    image_url: str | None = None
    meta_title: str | None = None
    meta_description: str | None = None
    seo_keywords: str | None = None
    name_en: str | None = None
    description_en: str | None = None
    meta_title_en: str | None = None
    meta_description_en: str | None = None
    seo_keywords_en: str | None = None
    sort_order: int = 0
    is_active: bool = True
    is_nav_visible: bool = True


class CategoryUpdate(BaseModel):
    name: str | None = None
    slug: str | None = None
    parent_id: int | None = None
    description: str | None = None
    image_url: str | None = None
    meta_title: str | None = None
    meta_description: str | None = None
    seo_keywords: str | None = None
    name_en: str | None = None
    description_en: str | None = None
    meta_title_en: str | None = None
    meta_description_en: str | None = None
    seo_keywords_en: str | None = None
    sort_order: int | None = None
    is_active: bool | None = None
    is_nav_visible: bool | None = None


@router.get("", response_model=list[CategoryOut])
async def list_categories(
    keyword: Optional[str] = Query(None),
    parent_id: Optional[int] = Query(None),
    db: AsyncSession = Depends(get_db),
    admin_user: User = Depends(get_admin_user),
):
    q = select(Category).where(Category.tenant_id == admin_user.tenant_id)
    if keyword:
        q = q.where(Category.name.ilike(f"%{keyword}%"))
    if parent_id is not None:
        q = q.where(Category.parent_id == parent_id)
    q = q.order_by(Category.sort_order, Category.id)
    result = await db.execute(q)
    cats = result.scalars().all()

    # 统计每个分类的商品数量
    count_result = await db.execute(
        select(Product.category_id, func.count(Product.id).label("cnt"))
        .where(Product.tenant_id == admin_user.tenant_id)
        .group_by(Product.category_id)
    )
    count_map = {row.category_id: row.cnt for row in count_result}

    out = []
    for c in cats:
        d = CategoryOut.model_validate(c)
        d.product_count = count_map.get(c.id, 0)
        d.is_active = bool(c.is_active)
        d.is_nav_visible = bool(c.is_nav_visible)
        out.append(d)
    return out


@router.post("", response_model=CategoryOut, status_code=status.HTTP_201_CREATED)
async def create_category(
    body: CategoryCreate,
    db: AsyncSession = Depends(get_db),
    admin_user: User = Depends(get_admin_user),
):
    existing = await db.execute(
        select(Category).where(Category.tenant_id == admin_user.tenant_id, Category.slug == body.slug)
    )
    if existing.scalar_one_or_none():
        raise HTTPException(status_code=400, detail="该 slug 已存在")

    if body.parent_id:
        parent = await db.execute(
            select(Category).where(Category.id == body.parent_id, Category.tenant_id == admin_user.tenant_id)
        )
        if not parent.scalar_one_or_none():
            raise HTTPException(status_code=400, detail="父分类不存在")

    data = body.model_dump(exclude={"name_en", "description_en", "meta_title_en", "meta_description_en", "seo_keywords_en"})
    data["is_active"] = 1 if data.get("is_active") else 0
    data["is_nav_visible"] = 1 if data.get("is_nav_visible") else 0
    cat = Category(tenant_id=admin_user.tenant_id, **data)
    cat.name_en = body.name_en or None
    cat.description_en = body.description_en or None
    cat.meta_title_en = body.meta_title_en or None
    cat.meta_description_en = body.meta_description_en or None
    cat.seo_keywords_en = body.seo_keywords_en or None
    db.add(cat)
    await bump_revision(db, admin_user.tenant_id)
    await db.commit()
    await db.refresh(cat)
    await cache_delete(f"categories:{admin_user.tenant_id}")
    d = CategoryOut.model_validate(cat)
    d.is_active = bool(cat.is_active)
    d.is_nav_visible = bool(cat.is_nav_visible)
    return d


class CategoryTranslateRequest(BaseModel):
    name: str = ""
    description: str = ""
    meta_title: str = ""
    meta_description: str = ""
    seo_keywords: str = ""


class CategoryTranslateResponse(BaseModel):
    name_en: str = ""
    description_en: str = ""
    meta_title_en: str = ""
    meta_description_en: str = ""
    seo_keywords_en: str = ""


@router.post("/translate", response_model=CategoryTranslateResponse, summary="AI翻译分类字段")
async def translate_category(
    body: CategoryTranslateRequest,
    db: AsyncSession = Depends(get_db),
    admin_user: User = Depends(get_admin_user),
):
    tid = admin_user.tenant_id
    s_r = await db.execute(select(TenantSettings).where(TenantSettings.tenant_id == tid))
    s = s_r.scalar_one_or_none()
    extra = (s.extra or {}) if s else {}
    if not extra.get("ai_enabled"):
        raise HTTPException(status_code=400, detail="AI 未启用，请在系统设置 → AI 配置中开启")
    extra = await resolve_ai_extra(db, tid, extra)
    await consume_ai_quota(db, tid)

    # Strip HTML and cap field lengths to keep the prompt small and avoid timeout
    desc_text = _strip_html(body.description, max_chars=400)
    system_prompt = (
        "You are a professional e-commerce translator. Translate the provided Chinese product category information into natural English. "
        "For SEO fields, produce search-engine-optimized copy. "
        "Return ONLY a valid JSON object with keys: name_en, description_en, meta_title_en, meta_description_en, seo_keywords_en. "
        "If a field is empty, return an empty string for it."
    )
    user_prompt = (
        f"Translate this category information from Chinese to English:\n"
        f"name: {(body.name or '')[:200]}\n"
        f"description: {desc_text}\n"
        f"meta_title: {(body.meta_title or '')[:160]}\n"
        f"meta_description: {(body.meta_description or '')[:320]}\n"
        f"seo_keywords: {(body.seo_keywords or '')[:300]}\n\n"
        f"Return JSON only, no explanation."
    )

    raw = await call_ai(user_prompt, extra, system_prompt=system_prompt, max_tokens=1024, timeout=120)
    start = raw.find("{")
    if start == -1:
        raise HTTPException(status_code=502, detail="AI 返回格式异常，请重试")
    try:
        data, _ = _json.JSONDecoder().raw_decode(raw, start)
    except _json.JSONDecodeError:
        raise HTTPException(status_code=502, detail="AI 返回 JSON 解析失败，请重试")

    return CategoryTranslateResponse(
        name_en=data.get("name_en", ""),
        description_en=data.get("description_en", ""),
        meta_title_en=data.get("meta_title_en", ""),
        meta_description_en=data.get("meta_description_en", ""),
        seo_keywords_en=data.get("seo_keywords_en", ""),
    )


@router.put("/{category_id}", response_model=CategoryOut)
async def update_category(
    category_id: int,
    body: CategoryUpdate,
    db: AsyncSession = Depends(get_db),
    admin_user: User = Depends(get_admin_user),
):
    result = await db.execute(
        select(Category).where(Category.id == category_id, Category.tenant_id == admin_user.tenant_id)
    )
    cat = result.scalar_one_or_none()
    if not cat:
        raise HTTPException(status_code=404, detail="分类不存在")

    updates = body.model_dump(exclude_unset=True)

    if "slug" in updates and updates["slug"] != cat.slug:
        dup = await db.execute(
            select(Category).where(
                Category.tenant_id == admin_user.tenant_id,
                Category.slug == updates["slug"],
                Category.id != category_id,
            )
        )
        if dup.scalar_one_or_none():
            raise HTTPException(status_code=400, detail="该 slug 已存在")

    if "parent_id" in updates and updates["parent_id"]:
        if updates["parent_id"] == category_id:
            raise HTTPException(status_code=400, detail="不能将自身设为父分类")

    for k, v in updates.items():
        if k in ("is_active", "is_nav_visible"):
            setattr(cat, k, 1 if v else 0)
        else:
            setattr(cat, k, v)

    await bump_revision(db, admin_user.tenant_id)
    await db.commit()
    await db.refresh(cat)
    await cache_delete(f"categories:{admin_user.tenant_id}")
    d = CategoryOut.model_validate(cat)
    d.is_active = bool(cat.is_active)
    d.is_nav_visible = bool(cat.is_nav_visible)
    return d


@router.delete("/{category_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_category(
    category_id: int,
    db: AsyncSession = Depends(get_db),
    admin_user: User = Depends(get_admin_user),
):
    result = await db.execute(
        select(Category).where(Category.id == category_id, Category.tenant_id == admin_user.tenant_id)
    )
    cat = result.scalar_one_or_none()
    if not cat:
        raise HTTPException(status_code=404, detail="分类不存在")

    # 检查是否有子分类
    children = await db.execute(
        select(func.count(Category.id)).where(Category.parent_id == category_id)
    )
    if children.scalar() > 0:
        raise HTTPException(status_code=400, detail="请先删除该分类下的所有子分类")

    await db.delete(cat)
    await bump_revision(db, admin_user.tenant_id)
    await db.commit()
    await cache_delete(f"categories:{admin_user.tenant_id}")
