"""应用 7 客户分析 Prompt 拼装。

消费链 App8 完成后串行触发，生成客户全量分析与运营策略。
- 数据源：fetch_member_consumption_data + fetch_member_notes
- 备注内容标注【来源：XXX，请甄别信息真实性】
- 输出字段：strategies 数组 + summary
- system prompt 在百炼控制台配置

返回：单个 prompt 字符串。
"""

from __future__ import annotations

import asyncio
import json
import logging
from typing import Any

from app.ai.cache_service import AICacheService
from app.ai.data_fetchers import fetch_member_consumption_data, fetch_member_notes
from app.ai.schemas import CacheTypeEnum
from app.services.runtime_context import as_runtime_business_now_str

logger = logging.getLogger(__name__)

_MAX_PROMPT_LEN = 5000


async def build_prompt(
    context: dict,
    cache_svc: AICacheService | None = None,
) -> str:
    """构建 App7 prompt 字符串。

    Args:
        context: site_id, member_id

    Returns:
        JSON 序列化后的 prompt 字符串
    """
    site_id = context["site_id"]
    member_id = context["member_id"]

    results = await asyncio.gather(
        fetch_member_consumption_data(site_id, member_id),
        fetch_member_notes(site_id, member_id),
        return_exceptions=True,
    )

    warnings: list[str] = []

    if isinstance(results[0], Exception):
        member_data = _default_member_data()
        warnings.append("消费数据获取失败")
        logger.warning("App7 消费数据获取失败: %s", results[0])
    else:
        member_data = results[0]

    notes_raw = results[1] if not isinstance(results[1], Exception) else []
    if isinstance(results[1], Exception):
        warnings.append("备注获取失败")
        logger.warning("App7 备注获取失败: %s", results[1])

    # 主观信息标注来源
    if notes_raw:
        annotated = []
        for note in notes_raw:
            recorded_by = note.get("recorded_by", "未知")
            n = dict(note)
            n["content"] = (
                f"{note.get('content', '')}"
                f"【来源：{recorded_by}，请甄别信息真实性】"
            )
            annotated.append(n)
        subjective_notes: Any = annotated
    else:
        subjective_notes = "该客户暂无主观备注信息"

    payload: dict[str, Any] = {
        "current_time": as_runtime_business_now_str(site_id, fmt="%Y-%m-%d %H:%M"),
        "member_id": member_id,
        "member_nickname": member_data.get("member_nickname", ""),
        "objective_data": {
            "consumption_records": member_data.get("consumption_records", []) or "该客户暂无消费记录",
            "member_cards": member_data.get("member_cards", []),
            "card_balance_total": member_data.get("card_balance_total", 0),
            "stored_value_balance_total": member_data.get("stored_value_balance_total", 0),
            "expected_visit_date": member_data.get("expected_visit_date"),
            "days_since_last_visit": member_data.get("days_since_last_visit"),
        },
        "subjective_data": {
            "notes": subjective_notes,
        },
        "reference": _build_reference(site_id, member_id, cache_svc),
    }

    if warnings:
        payload["_data_warnings"] = warnings

    return _truncate_payload(payload)


def _default_member_data() -> dict:
    return {
        "member_nickname": "",
        "consumption_records": [],
        "member_cards": [],
        "card_balance_total": 0,
        "stored_value_balance_total": 0,
        "expected_visit_date": None,
        "days_since_last_visit": None,
    }


def _build_reference(
    site_id: int,
    member_id: int,
    cache_svc: AICacheService | None,
) -> dict:
    """组装 App8 最新 + 最近 2 条历史。"""
    if cache_svc is None:
        return {}

    ref: dict = {}
    target_id = str(member_id)

    latest = cache_svc.get_latest(
        CacheTypeEnum.APP8_CLUE_CONSOLIDATED.value, site_id, target_id,
    )
    if latest:
        ref["app8_latest"] = {
            "result_json": latest.get("result_json"),
            "generated_at": latest.get("created_at"),
        }

    history = cache_svc.get_history(
        CacheTypeEnum.APP8_CLUE_CONSOLIDATED.value, site_id, target_id, limit=2,
    )
    if history:
        ref["app8_history"] = [
            {"result_json": h.get("result_json"), "generated_at": h.get("created_at")}
            for h in history
        ]

    return ref


def _truncate_payload(payload: dict) -> str:
    """按优先级截断 consumption_records → notes。"""
    text = json.dumps(payload, ensure_ascii=False, default=str)
    if len(text) <= _MAX_PROMPT_LEN:
        return text

    records = payload["objective_data"].get("consumption_records")
    if isinstance(records, list) and len(records) > 5:
        payload["objective_data"]["consumption_records"] = records[:5]
        payload["objective_data"]["_truncated"] = f"消费记录已截断，原始 {len(records)} 条"
        text = json.dumps(payload, ensure_ascii=False, default=str)
    if len(text) > _MAX_PROMPT_LEN:
        n = payload["subjective_data"].get("notes")
        if isinstance(n, list) and len(n) > 10:
            payload["subjective_data"]["notes"] = n[:10]
            payload["subjective_data"]["_truncated_notes"] = f"备注已截断，原始 {len(n)} 条"
            text = json.dumps(payload, ensure_ascii=False, default=str)
    return text
