from __future__ import annotations

import re
from typing import Any


TECHNICAL_MARKERS = (
    "http ",
    "http:",
    "http error",
    "httpsconnectionpool",
    "traceback",
    "exception",
    "request_id",
    "canonical_request",
    "x-sdk-date",
    "authorization",
    "apigw.",
    "forbidden",
    "unauthorized",
    "signature",
    "winerror",
    "filenotfounderror",
    "tcl data",
    "unknown encoding",
)


def _compact_text(value: Any) -> str:
    return re.sub(r"\s+", " ", str(value or "")).strip()


def _leading_action(text: str) -> str:
    """保留“读取账号资源失败”这类业务动作，去掉后面的接口原文。"""
    for sep in ("：", ":"):
        if sep not in text:
            continue
        head = text.split(sep, 1)[0].strip(" ：:")
        if 2 <= len(head) <= 40 and any("\u4e00" <= char <= "\u9fff" for char in head):
            return head.rstrip("。")
    return ""


def _with_action(action: str, reason: str) -> str:
    if action:
        return f"{action}。\n\n{reason}"
    return reason


def _looks_technical(text: str) -> bool:
    lower = text.lower()
    return any(marker in lower for marker in TECHNICAL_MARKERS) or bool(re.search(r"\b[45]\d\d\b", text))


def friendly_popup_text(message: Any) -> str:
    """把接口、运行库、网络异常转换成通俗中文弹窗，详细原文继续留在日志里。"""
    raw = _compact_text(message)
    if not raw:
        return ""

    action = _leading_action(raw)
    lower = raw.lower()

    if (
        "incorrect iam authentication" in lower
        or "verify ak sk signature failed" in lower
        or "apigw.0301" in lower
        or ("http 401" in lower and ("ak" in lower or "sk" in lower or "signature" in lower))
    ):
        return _with_action(
            action,
            "AK/SK 不正确或已失效。\n\n请重新复制正确的 AK/SK 后再试；如果是刚创建的密钥，请确认云控制台里该密钥已启用。",
        )

    if (
        "unauthorized" in lower
        or "invalid access" in lower
        or "invalid ak" in lower
        or "invalid secret" in lower
        or ("401" in lower and ("accesskey" in lower or "securitykey" in lower))
    ):
        return _with_action(action, "AK/SK 校验失败。\n\n请检查 AK/SK 是否复制完整，账号是否仍然启用。")

    if "forbidden" in lower or "http 403" in lower or "http error 403" in lower or "permission" in lower:
        return _with_action(
            action,
            "账号权限不足，或当前云平台暂时拒绝访问。\n\n请确认账号已开通相关云服务、余额和权限正常，然后再重试。",
        )

    if "10054" in lower or "connection reset" in lower or "远程主机强迫关闭" in raw:
        return _with_action(
            action,
            "网络连接被云平台临时断开。\n\n通常是网络波动或云接口限流导致，稍后重试即可；如果连续出现，请导出日志发给维护人员。",
        )

    if "timed out" in lower or "timeout" in lower or "read timed out" in lower:
        return _with_action(
            action,
            "连接云平台超时。\n\n请检查网络是否稳定，稍后重试；如果多个地区同时超时，建议先减少并发任务。",
        )

    if "unknown encoding: idna" in lower:
        return _with_action(
            action,
            "软件网络组件加载异常。\n\n请关闭软件后重新打开；如果仍然出现，请使用最新完整压缩包重新解压运行。",
        )

    if "tcl data" in lower or "tcl wasn't installed properly" in lower or "pyi_rth__tkinter" in lower:
        return _with_action(
            action,
            "软件运行库加载失败。\n\n请完整解压压缩包后再运行，不要单独复制 exe；如果仍然出现，请使用新版便携包。",
        )

    if "failed to remove temporary directory" in lower or "_mei" in lower:
        return _with_action(
            action,
            "软件临时目录正在被占用。\n\n一般不影响继续使用；关闭多余的软件窗口后重新打开即可。",
        )

    if "filenotfounderror" in lower or "no such file or directory" in lower:
        return _with_action(
            action,
            "软件所需文件缺失。\n\n请确认没有删除 source、data、_internal 等隐藏文件夹，并使用完整压缩包重新解压。",
        )

    http_match = re.search(r"http(?: error)?\s*([45]\d\d)", lower)
    if http_match:
        status = http_match.group(1)
        return _with_action(
            action,
            f"云平台接口返回异常（{status}）。\n\n请稍后重试；如果连续出现，请导出日志发给维护人员。",
        )

    if _looks_technical(raw):
        return _with_action(
            action,
            "任务执行时遇到异常。\n\n请稍后重试；如果连续出现，请点击“导出日志”，把日志压缩包发给维护人员。",
        )

    return str(message)
