"""应用 8：维客线索整理。

接收 App3（消费分析）和 App6（备注分析）的线索，
通过百炼 AI 整合去重，然后全量替换写入 member_retention_clue 表。

app_id = "app8_consolidation"
"""

from __future__ import annotations

import json
import logging

from app.ai.dashscope_client import DashScopeClient
from app.ai.cache_service import AICacheService
from app.ai.conversation_service import ConversationService
from app.ai.prompts.app8_consolidation_prompt import build_prompt
from app.ai.schemas import CacheTypeEnum
from app.database import get_connection

logger = logging.getLogger(__name__)

APP_ID = "app8_consolidation"


class ClueWriter:
    """维客线索全量替换写入器。

    DELETE source IN ('ai_consumption', 'ai_note') → INSERT 新线索（事务）。
    人工线索（source='manual'）不受影响。
    """

    def replace_ai_clues(
        self,
        member_id: int,
        site_id: int,
        clues: list[dict],
    ) -> int:
        """全量替换该客户的 AI 来源线索，返回写入数量。

        在单个事务中执行 DELETE + INSERT，失败时回滚保留原有线索。

        字段映射：
        - category → category
        - emoji + " " + summary → summary（如 "📅 偏好周末下午时段消费"）
        - detail → detail
        - providers → recorded_by_name
        - source: 根据 providers 判断（见 _determine_source）
        - recorded_by_assistant_id: NULL（系统触发）
        """
        conn = get_connection()
        try:
            with conn.cursor() as cur:
                # 1. 删除该客户所有 AI 来源线索
                cur.execute(
                    """
                    DELETE FROM member_retention_clue
                    WHERE member_id = %s AND site_id = %s
                      AND source IN ('ai_consumption', 'ai_note')
                    """,
                    (member_id, site_id),
                )

                # 2. 插入新线索
                for clue in clues:
                    emoji = clue.get("emoji", "")
                    raw_summary = clue.get("summary", "")
                    summary = f"{emoji} {raw_summary}" if emoji else raw_summary
                    source = _determine_source(clue.get("providers", ""))

                    cur.execute(
                        """
                        INSERT INTO member_retention_clue
                            (member_id, site_id, category, summary, detail,
                             source, recorded_by_name, recorded_by_assistant_id)
                        VALUES (%s, %s, %s, %s, %s, %s, %s, NULL)
                        """,
                        (
                            member_id,
                            site_id,
                            clue.get("category", ""),
                            summary,
                            clue.get("detail", ""),
                            source,
                            clue.get("providers", ""),
                        ),
                    )

                conn.commit()
                return len(clues)
        except Exception:
            conn.rollback()
            raise
        finally:
            conn.close()


def _determine_source(providers: str) -> str:
    """根据 providers 判断 source 值。

    - 纯 App3（providers 仅含"系统"）→ ai_consumption
    - 纯 App6（providers 不含"系统"）→ ai_note
    - 混合来源 → ai_consumption
    """
    if not providers:
        return "ai_consumption"
    provider_list = [p.strip() for p in providers.split(",")]
    has_system = "系统" in provider_list
    has_human = any(p != "系统" for p in provider_list if p)
    if has_system and not has_human:
        # 纯 App3（系统自动分析）
        return "ai_consumption"
    elif has_human and not has_system:
        # 纯 App6（人工备注分析）
        return "ai_note"
    else:
        # 混合来源
        return "ai_consumption"


async def run(
    context: dict,
    client: DashScopeClient,
    cache_svc: AICacheService,
    conv_svc: ConversationService,
) -> dict:
    """执行 App8 维客线索整理。

    流程：
    1. build_prompt 构建 Prompt
    2. bailian.chat_json 调用百炼
    3. 写入 conversation + messages
    4. 写入 ai_cache
    5. ClueWriter 全量替换 member_retention_clue
    6. 返回结果

    Args:
        context: site_id, member_id, app3_clues, app6_clues,
                 app3_generated_at, app6_generated_at
        bailian: 百炼客户端
        cache_svc: 缓存服务
        conv_svc: 对话服务

    Returns:
        百炼返回的结构化 JSON（clues 数组）
    """
    site_id = context["site_id"]
    member_id = context["member_id"]
    user_id = context.get("user_id", "system")
    nickname = context.get("nickname", "")

    # 1. 构建 Prompt
    messages = build_prompt(context)

    # 2. 创建对话记录
    conversation_id = conv_svc.create_conversation(
        user_id=user_id,
        nickname=nickname,
        app_id=APP_ID,
        site_id=site_id,
        source_context={"member_id": member_id},
    )

    # 写入 system + user 消息
    conv_svc.add_message(
        conversation_id=conversation_id,
        role="system",
        content=messages[0]["content"],
    )
    conv_svc.add_message(
        conversation_id=conversation_id,
        role="user",
        content=messages[1]["content"],
    )

    # 3. 调用百炼 API
    result, tokens_used = await bailian.chat_json(messages)

    # 4. 写入 assistant 消息
    conv_svc.add_message(
        conversation_id=conversation_id,
        role="assistant",
        content=json.dumps(result, ensure_ascii=False),
        tokens_used=tokens_used,
    )

    # 5. 写入缓存
    cache_svc.write_cache(
        cache_type=CacheTypeEnum.APP8_CLUE_CONSOLIDATED.value,
        site_id=site_id,
        target_id=str(member_id),
        result_json=result,
        triggered_by=f"user:{user_id}",
    )

    # 6. 全量替换 member_retention_clue
    clues = result.get("clues", [])
    if clues:
        writer = ClueWriter()
        written = writer.replace_ai_clues(member_id, site_id, clues)
        logger.info(
            "App8 线索写入完成: site_id=%s member_id=%s written=%d",
            site_id, member_id, written,
        )

    logger.info(
        "App8 线索整理完成: site_id=%s member_id=%s conversation_id=%s tokens=%d",
        site_id, member_id, conversation_id, tokens_used,
    )

    return result
