from __future__ import annotations

import asyncio
import logging
import os
import re
from typing import Any

from openai import AsyncOpenAI

from .config import OPENAI_API_KEY, OPENAI_BASE_URL, OPENAI_MODEL_NAME

logger = logging.getLogger(__name__)

VISION_MODEL = OPENAI_MODEL_NAME

ANALYZE_PROMPT = """
你是一个电商图片处理评估专家，同时也是 Gemini 图像生成提示词专家。
请仔细分析这张图片，输出以下字段，每行一个，不要多余内容：

敏感内容: <yes|no>
平整度: <flat|mild|rough>
含文字: <yes|no>
含人脸: <yes|no>
阴影: <yes|no>
复杂度: <simple|normal|complex|hard>
原因: <15字以内，说明复杂度判断依据>
主体: <图片核心内容，如：印花图案/logo/人物/产品/老照片/风景/文字/其他>
类型: <处理类型，如：印花提取/高清修复/去背景/老照片修复/logo提取/人像修复/其他>
质量: <原图质量，如：清晰/轻微模糊/严重模糊/低分辨率/截图/扫描件>
可做: <yes|partial|no>
风险: <none|low|high>
业务相关: <yes|no>
透视: <no|mild|strong>
比例: <从以下选一个最合适的：1:1 / 9:16 / 16:9 / 3:4 / 4:3 / 3:2 / 2:3 / 5:4 / 4:5>
提示词: <为 Gemini 写处理指令，中文，60字以内，说明要做什么、保留什么、去掉什么>
备注: <给客服AI的特别提示，没有则填无>

判断规则：

【报价核心：越平整越便宜】
- 平整度 flat：画面平整、无褶皱、无透视 → 便宜
- 平整度 mild：轻微褶皱/透视 → 中等
- 平整度 rough：有褶皱/透视/曲面 → 贵
- 含文字：大字没关系不加价；小字需精细保留/清晰化 → 加价（含文字填 yes 仅指有小字的情况）
- 含人脸 yes：有人脸 → 加价
- 阴影 yes：有明显阴影需处理 → 加价
综合以上因素，越平整、无小字、无人脸、无阴影 → 越便宜（simple）

【含文字】
- yes：含小字需精细保留/清晰化（小字难处理 → 加价）
- no：无文字，或仅有大字（大字没关系 → 不加价）

【文字数量加价规则】
- none：无文字，不加价
- 少量 (1-10 字)：+5 元
- 中量 (11-50 字)：+10-15 元
- 大量 (51-200 字)：+20-30 元
- 极多 (200 字以上)：+30-50 元

【文字分层需求】
- yes：客户要求可编辑分层文件（PSD 等） → 基础价格 x2 或 +50 元起
- no：普通图片处理 → 正常价格

【文字分层 + 大量文字】
- 如果 文字数量=大量/极多 且 文字分层需求=yes → 总价可达 60-80 元

【含人脸】
- yes：图中有真实人物面孔（人像照/集体照/证件照/老照片等）
- no：无人脸或人脸极小不影响主体

【风险评估 - 重要！】
- none：印花/图案/logo/风景/产品，AI处理效果稳定，可直接报价接单
- low：有人脸但清晰度尚可，AI修复后人脸相似度70-90%，可以接单但要说明风险
- high：以下任一情况 → 严重模糊的人脸照片/老照片人像/需要打印/客户问能否找回原图
  high情况下，可做改为partial，备注写明风险话术，谨慎接单

【敏感内容检测 - 必须严格判断！】
- yes：含以下任一内容 → 色情/黄色/擦边/裸露/性暗示/大尺度/涉政/暴力/血腥/违禁品/地图类
  敏感内容=yes 时，可做必须填 no，直接拒绝不接单
- no：无上述敏感内容，可以正常接单处理

【可做判断 - 决定是否接单】
- yes：效果有把握，可以接单处理
- partial：能处理但有明显限制（人脸变形风险/分辨率极低/严重损坏）→ 可以接单但要说明风险
- no：无法接单（纯黑/纯白/完全损坏/找原始 RAW 文件/敏感内容/违法内容）

【敏感内容】优先判断，若为 yes 则 可做 必填 no
- yes：图片含色情/黄色/擦边/裸露/性暗示/大尺度等违规内容
- no：无上述敏感内容

【可做判断】
- yes：效果有把握，可直接处理
- partial：能处理但有明显限制（人脸变形风险/分辨率极低/严重损坏）
- no：无法处理（纯黑/纯白/完全损坏/找原始RAW文件/敏感内容）

【业务相关判断 - 必须由你判断】
- yes：需求与印花/印刷素材处理，或高清修复业务相关
- no：与以上业务无关（例如闲聊、非图像处理诉求）
- 若业务相关=no，则可做必须填 no

【风险话术模板（备注字段）】
- 含人脸+需打印：AI修复后人脸可能有轻微变化，建议先看效果确认再打印
- 严重模糊人脸：这张模糊程度较高，修复后清晰了但人脸可能跟原来有差异
- 找原图：找不到原始文件，只能对现有图片做高清修复处理
- 完全损坏：这张无法处理

【透视判断】
- no：正面拍摄，无明显变形
- mild：轻微透视（衣服悬挂/桌面小角度斜拍）
- strong：严重透视（俯拍/贴墙/大角度倾斜）

【比例选择】
- 印花/图案/logo/正方形 -> 1:1
- 竖屏壁纸/短视频封面 -> 9:16
- 宽屏/横版视频 -> 16:9
- 移动广告/Instagram竖图 -> 4:5
- 竖向人像/海报/证件照 -> 3:4
- 竖向相机照片 -> 2:3
- 接近正方形产品图 -> 5:4
- 横向标准图/风景 -> 4:3
- 横向相机照片/产品实拍 -> 3:2

示例1（印花，无风险）：
敏感内容: no
平整度: mild
含文字: no
含人脸: no
阴影: no
复杂度: complex
原因: 印花细节密集颜色层次多
主体: 印花图案
类型: 印花提取
质量: 轻微模糊
可做: yes
风险: none
透视: mild
比例: 1:1
提示词: 提取衣物印花图案，去除褶皱和背景杂色，补全缺失部分，保持颜色细节100%还原，输出干净平面印花图
备注: 无

示例2（人像老照片，要打印）：
敏感内容: no
平整度: flat
含文字: no
含人脸: yes
阴影: no
复杂度: hard
原因: 严重模糊人脸细节丢失
主体: 人物照片
类型: 人像修复
质量: 严重模糊
可做: partial
风险: high
透视: no
比例: 3:4
提示词: 对模糊人像进行高清修复，增强细节，保持人物特征不变
备注: AI修复后人脸可能有轻微变化，建议先看效果确认满意再用于打印

示例3（平整印花，最便宜）：
敏感内容: no
平整度: flat
含文字: no
含人脸: no
阴影: no
复杂度: simple
原因: 画面平整无褶皱无文字无人脸
主体: 印花图案
类型: 印花提取
质量: 清晰
可做: yes
风险: none
透视: no
比例: 1:1
提示词: 提取印花图案，去除背景，输出干净平面图
备注: 无
"""


def _clip(text: str, n: int = 180) -> str:
    t = re.sub(r"\s+", " ", str(text or "")).strip()
    if len(t) <= n:
        return t
    return f"{t[:n]}..."


def _extract_line(text: str, key: str) -> str:
    m = re.search(rf"{re.escape(key)}\s*[:：]\s*(.+)", text or "")
    return m.group(1).strip() if m else ""


def _parse_result(text: str) -> dict[str, Any]:
    intent = _extract_line(text, "诉求类型")
    can_do = _extract_line(text, "可做").lower()
    complexity = _extract_line(text, "复杂度").lower()
    price_text = _extract_line(text, "建议报价")
    note = _extract_line(text, "说明")

    if intent not in {"找图", "高清修复", "其他"}:
        intent = "其他"
    if can_do not in {"yes", "partial", "no"}:
        can_do = "partial"
    if complexity not in {"simple", "normal", "complex", "hard"}:
        complexity = "normal"

    price = 0
    m = re.search(r"\d+", price_text or "")
    if m:
        price = int(m.group(0))

    return {
        "intent_type": intent,
        "can_do": can_do,
        "complexity": complexity,
        "price_suggest": price,
        "note": note or "已看图",
    }


async def analyze_image_for_quote(image_url: str, customer_text: str = "", goods_name: str = "") -> dict[str, Any]:
    """
    识图报价分析（用于 QuoteAgent 上下文增强）
    """
    image_url = str(image_url or "").strip()
    if not image_url:
        return {"ok": False, "error": "empty_image_url"}
    if not OPENAI_API_KEY:
        return {"ok": False, "error": "OPENAI_API_KEY 未配置"}

    model_name = VISION_MODEL
    client = AsyncOpenAI(base_url=OPENAI_BASE_URL, api_key=OPENAI_API_KEY)
    user_text = (
        f"客户文本: {customer_text or '无'}\n"
        f"商品标题: {goods_name or '无'}\n"
        "请按固定字段输出。"
    )
    logger.info("[识图报价] 豆包模型=%s 图片=%s 提示词=%s", model_name, image_url, _clip(ANALYZE_PROMPT, 90))
    try:
        resp = await asyncio.wait_for(
            client.chat.completions.create(
                model=model_name,
                temperature=0.1,
                messages=[
                    {"role": "system", "content": "你是电商图片识别报价助手。"},
                    {
                        "role": "user",
                        "content": [
                            {"type": "text", "text": f"{ANALYZE_PROMPT}\n{user_text}"},
                            {"type": "image_url", "image_url": {"url": image_url}},
                        ],
                    },
                ],
            ),
            timeout=30,
        )
        text = str((resp.choices[0].message.content if resp and resp.choices else "") or "").strip()
        logger.info("[识图报价] 模型输出=%s", _clip(text, 260))
        parsed = _parse_result(text)
        parsed["ok"] = True
        parsed["raw"] = text
        return parsed
    except Exception as e:
        logger.error("[识图报价] 调用失败: %s", e)
        return {"ok": False, "error": str(e)}

