"""Store AI 客服路由 — SSE 流式对话 + 配置查询"""
import asyncio
import json
from fastapi import APIRouter, Depends, HTTPException
from fastapi.responses import StreamingResponse
from pydantic import BaseModel
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select

from app.api.deps import get_db, get_optional_customer, get_tenant_by_domain
from app.config import settings
from app.core.models.customer import Customer
from app.core.models.tenant_settings import TenantSettings
from app.core.models.product import Product
from app.core.models.article import Article
from app.core.ai_utils import call_ai_stream, strip_think_blocks, resolve_ai_extra
from app.core.services.ai_quota import consume_ai_quota
from app.core.ai_chat_service import (
    build_system_prompt,
    apply_sliding_window,
    fetch_product_context,
    fetch_order_context,
    fetch_promotion_context,
    fetch_tracking_context,
    filter_blacklist,
    get_product_ai_context,
    get_expiry_warning_days,
    load_effective_expiry_dates,
    get_member_level,
    RULE_REMINDER,
)
router = APIRouter(prefix="/store/ai-chat", tags=["AI客服"])


async def _get_settings(db: AsyncSession, tenant_id: int) -> TenantSettings | None:
    result = await db.execute(
        select(TenantSettings).where(TenantSettings.tenant_id == tenant_id)
    )
    return result.scalar_one_or_none()


class ChatMessage(BaseModel):
    role: str
    content: str


class ProductContext(BaseModel):
    product_id: int | None = None
    product_name: str | None = None


class PageContext(BaseModel):
    type: str | None = None
    path: str | None = None
    entity_id: int | None = None
    slug: str | None = None
    title: str | None = None
    summary: str | None = None


class ChatRequest(BaseModel):
    messages: list[ChatMessage]
    product_context: ProductContext | None = None
    page_context: PageContext | None = None


def _short_text(value: str | None, limit: int = 700) -> str:
    text = " ".join(str(value or "").split())
    if len(text) <= limit:
        return text
    return text[:limit].rstrip() + "..."


def build_page_context_prompt(page: PageContext | None, enriched: str = "") -> str:
    if not page and not enriched:
        return ""
    lines = ["[Current page context]"]
    if page:
        if page.type:
            lines.append(f"- page_type: {_short_text(page.type, 80)}")
        if page.path:
            lines.append(f"- path: {_short_text(page.path, 180)}")
        if page.entity_id:
            lines.append(f"- entity_id: {page.entity_id}")
        if page.slug:
            lines.append(f"- slug: {_short_text(page.slug, 180)}")
        if page.title:
            lines.append(f"- title: {_short_text(page.title, 220)}")
        if page.summary:
            lines.append(f"- summary: {_short_text(page.summary, 700)}")
    if enriched:
        lines.append(_short_text(enriched, 1200))
    return "\n".join(lines)


async def fetch_page_context(
    db: AsyncSession,
    page: PageContext | None,
    tid: int,
    member_level,
) -> str:
    if not page:
        return ""

    page_type = (page.type or "").lower()
    enriched = ""
    if page_type == "product_detail" and (page.entity_id or page.slug):
        conditions = [Product.tenant_id == tid, Product.status == "active"]
        if page.entity_id:
            conditions.append(Product.id == page.entity_id)
        elif page.slug:
            conditions.append(Product.slug == page.slug)
        result = await db.execute(select(Product).where(*conditions))
        p = result.scalar_one_or_none()
        if p:
            from app.core.ai_chat_service import _load_products_with_price
            pairs = await _load_products_with_price(db, [p], member_level)
            _, eff_price = pairs[0]
            warning_days = await get_expiry_warning_days(db, tid)
            expiry_dates = await load_effective_expiry_dates(db, [p])
            enriched = (
                f"Current product from database: name={p.name}, slug={p.slug}, id={p.id}, "
                f"price={eff_price}, stock={p.stock_qty}. {get_product_ai_context(p, expiry_dates.get(p.id), warning_days)}"
            )
    elif page_type in {"article_detail", "blog_detail", "project_detail"} and page.slug:
        result = await db.execute(
            select(Article).where(
                Article.tenant_id == tid,
                Article.slug == page.slug,
                Article.status == "published",
            )
        )
        article = result.scalar_one_or_none()
        if article:
            title = article.title_en or article.title
            excerpt = article.excerpt_en or article.excerpt or article.seo_description_en or article.seo_description or ""
            enriched = f"Current article from database: {title}. {_short_text(excerpt, 600)}"

    return build_page_context_prompt(page, enriched)


@router.get("/config", summary="获取客服配置（公开）")
async def get_chat_config(
    db: AsyncSession = Depends(get_db),
    tid: int = Depends(get_tenant_by_domain),
):
    s = await _get_settings(db, tid)
    extra = (s.extra or {}) if s else {}
    return {
        "enabled": bool(extra.get("ai_chat_enabled", False)),
        "name": extra.get("ai_chat_name") or "客服",
        "name_en": extra.get("ai_chat_name_en") or None,
        "welcome": extra.get("ai_chat_welcome") or "您好！有什么可以帮您？",
        "welcome_en": extra.get("ai_chat_welcome_en") or None,
    }


@router.post("/stream", summary="SSE 流式对话")
async def chat_stream(
    body: ChatRequest,
    db: AsyncSession = Depends(get_db),
    customer: Customer | None = Depends(get_optional_customer),
    tid: int = Depends(get_tenant_by_domain),
):
    s = await _get_settings(db, tid)
    extra = (s.extra or {}) if s else {}

    if not extra.get("ai_chat_enabled", False):
        async def disabled():
            yield 'data: {"delta": "AI 客服暂未开启，请联系商家。", "done": false}\n\n'
            yield 'data: {"delta": "", "done": true}\n\n'
        return StreamingResponse(disabled(), media_type="text/event-stream")

    extra = await resolve_ai_extra(db, tid, extra)
    try:
        await consume_ai_quota(db, tid)
    except HTTPException as quota_exc:
        if quota_exc.status_code == 429:
            exhausted_msg = extra.get("ai_exhausted_message") or "AI assistant is temporarily unavailable, please try again later."
            async def _exhausted():
                yield f'data: {json.dumps({"delta": exhausted_msg, "done": False}, ensure_ascii=False)}\n\n'
                yield 'data: {"delta": "", "done": true}\n\n'
            return StreamingResponse(_exhausted(), media_type="text/event-stream")
        raise
    shop_name = (s.store_name if s else "") or "本店"
    chat_name = extra.get("ai_chat_name") or "客服"
    faq       = extra.get("ai_chat_faq") or ""
    blacklist = extra.get("ai_chat_blacklist") or ""

    last_user_msg = ""
    for m in reversed(body.messages):
        if m.role == "user":
            last_user_msg = m.content
            break

    member_level = await get_member_level(db, customer)
    member_level_name = member_level.name if member_level else ""

    if body.product_context and body.product_context.product_id:
        result = await db.execute(
            select(Product).where(Product.id == body.product_context.product_id)
        )
        p = result.scalar_one_or_none()
        if p:
            from app.core.ai_chat_service import _effective_price, _load_products_with_price
            from app.core.models.currency import Currency
            _sym_r = await db.execute(
                select(Currency.symbol).where(Currency.tenant_id == tid, Currency.is_default == 1).limit(1)
            )
            _sym = _sym_r.scalar_one_or_none() or ""
            pairs = await _load_products_with_price(db, [p], member_level)
            _, eff_price = pairs[0]
            warning_days = await get_expiry_warning_days(db, tid)
            expiry_dates = await load_effective_expiry_dates(db, [p])
            price_display = f"{_sym}{eff_price}（原价{_sym}{p.base_price}，{member_level_name}专享）" if (member_level and eff_price < p.base_price) else f"{_sym}{eff_price}"
            product_ctx = f"【当前商品】《{p.name}|{p.slug}|{p.id}》（{price_display}，库存{p.stock_qty}）：{get_product_ai_context(p, expiry_dates.get(p.id), warning_days)}"
        else:
            product_ctx = ""
    else:
        product_ctx = await fetch_product_context(db, last_user_msg, tid, member_level)

    order_ctx = await fetch_order_context(db, customer)

    promo_ctx = await fetch_promotion_context(db, tid)

    page_ctx = await fetch_page_context(db, body.page_context, tid, member_level)

    try:
        tracking_ctx = await asyncio.wait_for(
            fetch_tracking_context(db, customer, tid, last_user_msg),
            timeout=5.0,
        )
    except asyncio.TimeoutError:
        async def _tracking_waiting():
            msg = "正在为您查询物流信息，请耐心等待，稍后可再次询问。"
            yield f'data: {json.dumps({"delta": msg, "done": False}, ensure_ascii=False)}\n\n'
            yield 'data: {"delta": "", "done": true}\n\n'
        return StreamingResponse(
            _tracking_waiting(),
            media_type="text/event-stream",
            headers={"Cache-Control": "no-cache", "X-Accel-Buffering": "no"},
        )

    system_prompt = build_system_prompt(
        shop_name, chat_name, faq, product_ctx, order_ctx, promo_ctx, member_level_name,
        page_ctx=page_ctx, tracking_ctx=tracking_ctx,
    )

    history = [{"role": m.role, "content": m.content} for m in body.messages]
    if history and history[-1]["role"] == "user":
        current_user_msg = history[-1]["content"]
        history = history[:-1]
    else:
        current_user_msg = last_user_msg

    history, was_truncated = apply_sliding_window(history)
    if was_truncated:
        system_prompt += f"\n\n{RULE_REMINDER}"

    messages = [{"role": "system", "content": system_prompt}]
    messages.extend(history)
    messages.append({"role": "user", "content": current_user_msg})

    async def generate():
        full_reply = ""
        async for delta in strip_think_blocks(call_ai_stream(messages, extra)):
            if delta.startswith("[ERROR]"):
                payload = json.dumps({"delta": delta, "done": False}, ensure_ascii=False)
                yield f"data: {payload}\n\n"
                break
            full_reply += delta
            payload = json.dumps({"delta": delta, "done": False}, ensure_ascii=False)
            yield f"data: {payload}\n\n"

        filtered = filter_blacklist(full_reply, blacklist)
        if filtered != full_reply:
            extra_msg = "\n\n（抱歉，我只能为您介绍本店商品。）"
            payload = json.dumps({"delta": extra_msg, "done": False}, ensure_ascii=False)
            yield f"data: {payload}\n\n"

        yield 'data: {"delta": "", "done": true}\n\n'

    return StreamingResponse(
        generate(),
        media_type="text/event-stream",
        headers={"Cache-Control": "no-cache", "X-Accel-Buffering": "no"},
    )
