"""外卖比价业务透传端点。

把客户端的 POST /api/v1/intent/recognize 和 /api/v1/price/step 请求原样转发给
pricebot-backend 的 /api/intent/recognize 和 /api/price/step。MVP 阶段**不鉴权**
(同 coupon/step,见 docs/待办与技术债.md P1:device_id 透传区分设备,待补 JWT +
device_id↔user_id 绑定后才能做用户级画像)。

- Phase 1 /intent/recognize:从源平台(淘宝闪购/美团/京东外卖)购物车页识别店名+菜品+
  价格,一次性。
- Phase 2 /price/step:多轮循环,在目标平台复现订单读到手价,直到 done。

真正的目标驱动比价逻辑在 pricebot-backend(GoalEngine,另一个 repo),本接口只是透传壳。
电商(ecom)那两个端点 food MVP 暂不需要,以后放开 scene 时再加 /ecom/intent/recognize
和 /ecom/step 两行即可。

pricebot 协议文档:
  pricebot-backend/docs/main/02_api_protocol.md
"""
from __future__ import annotations

import json
import logging
from typing import Any

import httpx
from fastapi import APIRouter, HTTPException, Request, status

from app.core.config import settings
from app.core.pricebot_client import get_pricebot_client
from app.core.pricebot_router import pick_pricebot

logger = logging.getLogger("shagua.compare")

router = APIRouter(prefix="/api/v1", tags=["compare"])


async def _passthrough(request: Request, upstream_path: str) -> dict[str, Any]:
    """把请求体原样转发给 pricebot-backend 的 {upstream_path}。

    跟 coupon_step 同款透传壳:不鉴权、不做 schema 校验,仅读 device_id/trace_id/step
    打日志。比价单帧是大上下文 / 逐帧 LLM,超时用 PRICEBOT_COMPARE_TIMEOUT_SEC(60s,
    比领券的 30s 长)。
    """
    # 读原始字节,避免"反序列化→再序列化"的双重 JSON(省 ~一半透传 CPU,让 app-server
    # 单 worker 也扛得住高并发)。只 json.loads 一次拿 trace_id 做亲和 + 打日志,转发时
    # 直接发原始 bytes(content=raw),不重新 dumps。
    raw = await request.body()
    try:
        meta = json.loads(raw)
    except Exception as e:
        raise HTTPException(status_code=400, detail=f"invalid json body: {e}") from e
    if not isinstance(meta, dict):
        meta = {}

    # 按 trace_id 一致性 hash 选 pricebot 实例(同一比价的所有帧落同一进程,内存维护 state)
    base = pick_pricebot(meta.get("trace_id"))
    url = f"{base.rstrip('/')}{upstream_path}"
    timeout = settings.PRICEBOT_COMPARE_TIMEOUT_SEC

    logger.info(
        "compare %s device_id=%s trace_id=%s step=%s",
        upstream_path,
        meta.get("device_id"),
        meta.get("trace_id"),
        meta.get("step"),
    )

    try:
        client = get_pricebot_client()
        resp = await client.post(
            url, content=raw, headers={"Content-Type": "application/json"}, timeout=timeout
        )
    except httpx.RequestError as e:
        logger.error("[pricebot] request failed: %s", e)
        raise HTTPException(
            status_code=status.HTTP_502_BAD_GATEWAY,
            detail=f"pricebot upstream unreachable: {e}",
        ) from e

    if resp.status_code >= 500:
        logger.error(
            "[pricebot] 5xx status=%d body=%s",
            resp.status_code,
            resp.text[:500],
        )
        raise HTTPException(
            status_code=status.HTTP_502_BAD_GATEWAY,
            detail=f"pricebot upstream returned {resp.status_code}",
        )

    return resp.json()


@router.post("/intent/recognize", summary="外卖比价 Phase 1 意图识别 (透传到 pricebot)")
async def intent_recognize(request: Request) -> dict[str, Any]:
    return await _passthrough(request, "/api/intent/recognize")


@router.post("/intent/step", summary="外卖比价 Phase 1 多帧意图识别 (透传到 pricebot, 仅淘宝源)")
async def intent_step(request: Request) -> dict[str, Any]:
    # 多帧版意图识别(展开+滚动采集→提取): 循环调用直到 done(done 帧顶层带
    # result+calibration)。目前仅淘宝源走这条, 其它源走上面单次 /intent/recognize。
    return await _passthrough(request, "/api/intent/step")


@router.post(
    "/intent/precoupon/step",
    summary="外卖比价 Phase 0 意图识别前先用券 (透传到 pricebot, 仅美团源)",
)
async def intent_precoupon_step(request: Request) -> dict[str, Any]:
    # 美团源平台『意图识别前先用券』多帧循环: 客户端在调 /intent/recognize 之前先循环
    # 调本端点到 done(continue=false)。订单页底部有『点击使用X红包』就自动选最大免费券
    # 用上, 已用券/无券则首帧秒过。与 /intent/step 同属 intent 域, 复用同一透传壳。
    return await _passthrough(request, "/api/intent/precoupon/step")


@router.post("/price/step", summary="外卖比价 Phase 2 步进 (透传到 pricebot)")
async def price_step(request: Request) -> dict[str, Any]:
    return await _passthrough(request, "/api/price/step")


@router.post("/trace/finalize", summary="比价 trace 收尾上云 (透传到 pricebot, 终止/未识别拿 trace_url)")
async def trace_finalize(request: Request) -> dict[str, Any]:
    # 用户终止 / Phase1 未识别没走到 done 帧, pricebot 没上云也没回传 trace_url。客户端收尾时
    # 打这个, _passthrough 按 trace_id 一致性 hash 落到处理这条 trace 的同一 pricebot 进程
    # (dir_cache 在那, 才能算对 trace 目录), 由后者打包上云返回 {trace_url}。
    return await _passthrough(request, "/api/trace/finalize")
