# -*- coding: utf-8 -*-
"""
AI 工作流服务 (Dify BaaS 版本)
事件驱动的异步 AI 任务：从客户沟通日志中自动提取标签和生成跟进待办。

架构要点：
- 此函数由 FastAPI BackgroundTasks 调用，运行在独立的后台线程中
- 必须使用独立的 DB Session 生命周期，严禁与主请求共享 Session
- AI 调用通过 Dify 平台 API（非直连大模型）
- AI 解析失败时静默降级（记录日志），绝不抛出异常导致主线程崩溃
"""

import json
import logging
import uuid

from app.core.dify_client import dify_client
from app.core.database import AsyncSessionLocal
from app.models.crm_business import CustomerTag, FollowUpToDo

from app.core.config import settings

logger = logging.getLogger("ai_workflow")


async def process_log_with_ai(
    log_id: uuid.UUID,
    content: str,
    customer_id: uuid.UUID,
) -> None:
    """
    后台 AI 任务：分析沟通日志，提取标签和待办。

    *** 关键约束 ***
    此函数在 BackgroundTasks 中执行，必须：
    1. 使用独立的 AsyncSession（不与主请求共享）
    2. 内部捕获所有异常，不向外抛出
    3. AI 返回格式异常时静默降级
    """
    logger.info("开始 AI 处理: log_id=%s, customer_id=%s", log_id, customer_id)

    if not settings.DIFY_LOG_APP_API_KEY:
        logger.error("DIFY_LOG_APP_API_KEY 未配置，跳过 AI 处理")
        return

    # ---- 独立的 DB Session 生命周期 ----
    async with AsyncSessionLocal() as db:
        try:
            # Step 1: 调用 Dify 日志分析 Workflow App
            # *** inputs 的键名必须与 Dify 后台配置的变量名对齐 ***
            # 在 Dify 后台的 Workflow 编排中，需定义输入变量 "log_content"
            workflow_outputs = await dify_client.call_workflow(
                api_key=settings.DIFY_LOG_APP_API_KEY,
                inputs={"log_content": content},
            )

            if not workflow_outputs:
                logger.warning("Dify 返回空响应，跳过入库 (log_id=%s)", log_id)
                return

            # Workflow 返回的是 dict，序列化为 JSON 字符串以兼容现有解析管线
            if isinstance(workflow_outputs, dict):
                raw_response = json.dumps(workflow_outputs, ensure_ascii=False)
            else:
                raw_response = str(workflow_outputs)

            logger.debug("Dify Workflow 原始返回: %s", raw_response[:500])

            # Step 2: 解析 JSON 响应 (容错)
            json_str = _extract_json(raw_response)
            result = json.loads(json_str)

            tags: list[str] = result.get("tags", [])
            next_task: str = result.get("next_task", "")

            # Step 3: 写入标签 (最多 3 个)
            if tags:
                for tag_name in tags[:3]:
                    tag_name = tag_name.strip()
                    if not tag_name:
                        continue
                    tag = CustomerTag(
                        customer_id=customer_id,
                        tag_name=tag_name,
                    )
                    db.add(tag)
                logger.info("写入 %d 个标签: %s", len(tags[:3]), tags[:3])

            # Step 4: 写入跟进待办
            if next_task and next_task.strip():
                todo = FollowUpToDo(
                    customer_id=customer_id,
                    task_desc=next_task.strip(),
                    status="pending",
                )
                db.add(todo)
                logger.info("写入待办: %s", next_task.strip()[:100])

            await db.commit()
            logger.info("AI 处理完成: log_id=%s", log_id)

        except json.JSONDecodeError as e:
            logger.error(
                "Dify 返回 JSON 解析失败 (log_id=%s): %s | 原始响应: %s",
                log_id, e, raw_response[:300],
            )
            await db.rollback()

        except Exception as e:
            logger.error(
                "AI 后台任务异常 (log_id=%s): %s",
                log_id, e, exc_info=True,
            )
            await db.rollback()


def _extract_json(text: str) -> str:
    """
    从 Dify/LLM 响应中提取 JSON 字符串。
    处理常见的"包裹"行为：
    - 直接返回 JSON
    - 用 ```json ... ``` 包裹
    - 在 JSON 前后加解释文字
    """
    text = text.strip()

    # 尝试提取 ```json ... ``` 代码块
    if "```json" in text:
        start = text.index("```json") + len("```json")
        end = text.index("```", start)
        return text[start:end].strip()

    if "```" in text:
        start = text.index("```") + len("```")
        end = text.index("```", start)
        return text[start:end].strip()

    # 尝试找到第一个 { 和最后一个 }
    first_brace = text.find("{")
    last_brace = text.rfind("}")
    if first_brace != -1 and last_brace != -1 and last_brace > first_brace:
        return text[first_brace:last_brace + 1]

    # 原样返回，让 json.loads 报错触发容错
    return text
