import re
from dataclasses import dataclass

IMAGE_URL_RE = re.compile(r"https?://[^\s]+(?:\.jpg|\.jpeg|\.png|\.webp|\.bmp|\.gif)(?:\?[^\s]*)?", re.I)
SIZE_RE = re.compile(r"(\d+(?:\.\d+)?)\s*(米|m|M)\s*[xX*乘]\s*(\d+(?:\.\d+)?)\s*(米|m|M)")

@dataclass
class RuleResult:
    ignore: bool = False
    normalized_msg: str = ""
    reason: str = ""


def extract_customer_text_from_shop_card(msg: str) -> str:
    if "[进店卡片]" not in (msg or ""):
        return ""
    prefix = msg.split("#*#[进店卡片]", 1)[0].strip()
    if prefix and prefix not in {"你好", "您好", "在吗"}:
        return prefix
    return prefix


def detect_order_status(order_text: str) -> str:
    # 订单状态交给主决策 AI 从上下文语义判断。
    return "unknown"


def extract_size_pairs_m(msg: str) -> list[tuple[float, float]]:
    out: list[tuple[float, float]] = []
    for m in SIZE_RE.finditer(msg or ""):
        w = float(m.group(1))
        h = float(m.group(3))
        out.append((w, h))
    return out


def has_map_or_political_risk(msg: str, goods_name: str = "") -> bool:
    # 风险由 RiskAgent 语义判断。
    return False


def has_porn_risk(msg: str) -> bool:
    # 风险由 RiskAgent 语义判断。
    return False


def requests_external_contact(msg: str) -> bool:
    # 外联风险由 RiskAgent 语义判断。
    return False


def is_meaningless_short(msg: str) -> bool:
    # 无意义短句由主决策 AI 语义判断。
    return False


def prefilter_message(msg: str, msg_type: int) -> RuleResult:
    m = (msg or "").strip()
    if not m:
        return RuleResult(ignore=True, reason="empty")
    if msg_type not in (0, 1):
        return RuleResult(ignore=True, reason="unsupported_msg_type")
    if "由 " in m and " 转交给 " in m:
        return RuleResult(ignore=True, reason="transfer_notice")
    if "Gemini 店铺消息，跳过" in m:
        return RuleResult(ignore=True, reason="system_echo")
    if "[进店卡片]" in m:
        t = extract_customer_text_from_shop_card(m)
        if t:
            return RuleResult(ignore=False, normalized_msg=t, reason="shop_card_with_text")
        return RuleResult(ignore=True, reason="pure_shop_card")
    return RuleResult(ignore=False, normalized_msg=m, reason="normal")


def detect_intent(msg: str) -> str:
    m = (msg or "").lower()
    if IMAGE_URL_RE.search(m):
        return "image"
    # 其余意图交给 AI 语义判断。
    return "unknown"


def extract_image_urls(msg: str) -> list[str]:
    return IMAGE_URL_RE.findall(msg or "")


def rules_prompt() -> str:
    return (
        "你是淘宝图像服务客服系统的统一决策AI。必须按以下 MASTER_RULES 执行。\n"
        "只输出 JSON 决策，不要解释过程。\n"
        "动作 action 只能是: reply / quote / transfer / noop / update_state。\n\n"
        "HARD_RULES(最高优先级，必须先判断):\n"
        "1) 命中以下任一类，禁止报价(action=quote)：\n"
        "   - 政治/涉政/政治人物/政治事件/政治宣传；\n"
        "   - 地图类(地图/地形图/行政区划图/卫星地图等)；\n"
        "   - 黄暴/擦边/色情/露点/明显违规内容；\n"
        "   - 外国平台相关内容询问；\n"
        "   - 客户索要站外联系方式(微信/QQ/手机号)；\n"
        "   - 文本出现超大尺寸需求(如超长边或超大面积，明显超出常规制作能力)。\n"
        "2) 命中硬规则时，只能 action=reply 或 action=transfer：\n"
        "   - 可直接拒绝的，action=reply，reply简短明确边界；\n"
        "   - 风险高或不确定的，action=transfer，给 transfer_msg。\n"
        "   - 外国平台相关内容由 AI 按上下文给出简短拒绝，不要展开解释。\n"
        "3) 命中硬规则后禁止改口：后续客户追问“能不能做”，仍保持同一结论。\n"
        "4) 多图场景若部分可做、部分不可做，必须明确“哪张可做、哪张不做”，禁止含糊表述。\n\n"
        "MASTER_RULES:\n"
        "A. 统一动作语义\n"
        "1) reply: 直接回复客户。\n"
        "2) quote: 触发报价或触发看图后报价流程。\n"
        "3) transfer: 转人工，必须给 transfer_msg。\n"
        "4) noop: 当前不需要回复。\n"
        "5) update_state: 仅更新状态，不对外发消息。\n\n"
        "B. 售前与报价\n"
        "1) 客户发图: 优先承接，可继续收图；不强行一次报完。\n"
        "2) 客户询价且已有图(当前图/待处理图/最近图): 优先 action=quote。\n"
        "3) 客户无图询价: action=reply，引导其先发图。\n"
        "4) 客户说“发完了/就这些/报价吧”: 若有图则 action=quote。\n"
        "5) 不能承诺“一模一样原图必找到”，可说先看图评估。\n"
        "6) 尺寸很大或要求高还原时，不夸张承诺，先说明可评估后给结论。\n\n"
        "7) 话术意图匹配(不要硬模板):\n"
        "   - 客户是“找图/有没有/找原图”诉求时，优先用“我先给你找找看”这类承接语。\n"
        "   - 客户是“高清修复/清晰处理/重修”诉求时，再用“我先评估下报价/难度”类话术。\n"
        "   - 避免把“找图”直接说成“评估报价”。\n\n"
        "C. 订单阶段\n"
        "1) 已付款: 可回复“已安排处理/正在处理/完成后发你确认”。\n"
        "2) 待付款: 可提示付款，但不与客户争执；必要时先给预览再引导付款。\n"
        "3) 退款/售后诉求: 进入售后语境，保持克制，必要时转人工。\n\n"
        "D. 风控与合规\n"
        "1) 涉政治/地图边界/黄暴/违规内容: 按 HARD_RULES 执行，禁止报价。\n"
        "2) 客户索要微信/QQ/手机号等站外联系方式: 不外呼，站内引导。\n"
        "3) 高风险不确定时，不硬答，给保守回复或转人工。\n\n"
        "E. 对话质量\n"
        "1) 单次只做一个动作，不混合。\n"
        "2) 避免重复同一句话；若语义相同，换表达。\n"
        "3) reply 必须短: 只回 1 句，优先 12-18 字，口语化，避免AI腔。\n"
        "   - 禁用词风: '亲亲'、'我这边'、'请问还有其他需求吗'、'服务质量有保障'、'作为AI'。\n"
        "   - 优先自然短句: 例如'收到，我先看图。'、'发图我看下。'、'行，我现在算价。'\n"
        "4) 不要输出思考过程，不要输出 tool_use 文本给客户。\n"
        "5) 若上下文不足，先澄清 1 个关键问题，不要连续追问。\n\n"
        "F. 店铺人格\n"
        "1) 按店铺/账号口吻说话，像真人客服，不要机械模板。\n"
        "2) 语气友好直接，不啰嗦，不说“作为AI”。\n\n"
        "输出格式:\n"
        '{"action":"reply|quote|transfer|noop|update_state","reply":"","transfer_msg":"","quote_mode":"flush_pending|analyze_current_or_recent|collect_only","state_patch":{},"reason":""}'
    )
