from __future__ import annotations

import re
from typing import Dict, List, Sequence, Tuple

from common.shared import REGION_PLANS, localize_region_tokens


def huawei_existing_ecs_guard_error(text: str) -> bool:
    """识别旧后端为避免重复购买 ECS 而主动拦截的提示。"""
    lower = str(text or "").lower()
    return (
        "已发现同地区已有满足配置的运行中云服务器" in lower
        or "为避免重复购买ecs" in lower
        or "旧ecs" in lower and "检查失败" in lower
    )


def huawei_retryable_reconcile_error(text: str) -> bool:
    """判断华为云旧后端补齐/反查失败是否适合继续重试。"""
    lower = str(text or "").lower()
    if not lower:
        return False
    # EIP 地址池售罄是华为云明确业务结果，不属于网络抖动；保留已买资源，避免外层继续重复购买/反查。
    sold_out_tokens = (
        "vpc.0532",
        "eip pool has been sold out",
        "no more ip addresses can be allocated",
        "public ip sold out",
        "公网ip售罄",
        "弹性公网ip售罄",
        "eip售罄",
    )
    if any(token in lower for token in sold_out_tokens):
        return False
    quota_stop_tokens = (
        "flavor_contain_subeni",
        "vpc.9905",
        "quota exceeded",
        "配额不足",
        "超过配额",
        "达到配额",
        "已达配额",
    )
    if any(token in lower for token in quota_stop_tokens):
        return False
    hard_plan_stop_tokens = (
        "固定网卡规划冲突",
        "必须是标准弹性网卡",
        "硬性配置",
        "不会继续漂移到其它 ip",
    )
    if any(token in lower for token in hard_plan_stop_tokens):
        return False
    retry_tokens = (
        "connectionexception",
        "connection aborted",
        "connection reset",
        "connection refused",
        "read timed out",
        "timeout",
        "10053",
        "10054",
        "temporarily",
        "资源反查未确认",
        "云上暂未发现满足",
        "暂未发现满足",
        "等待云服务器就绪超时",
        "等待主网卡端口",
        "网络连接失败",
        "httpsconnectionpool",
        "max retries exceeded",
    )
    return any(token in lower for token in retry_tokens)


def huawei_autobuy_created_server(output_lines: Sequence[str]) -> bool:
    """从旧后端输出里判断是否已经创建出云服务器 ID。"""
    joined = "\n".join(str(line or "") for line in output_lines[-240:])
    if not joined:
        return False
    if not any(marker in joined for marker in ("服务器ID列表", "服务器ID:", "云服务器ID", "server_id", "server id")):
        return False
    return bool(re.search(r"\b[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\b", joined, flags=re.I))


def _region_label_to_key() -> Dict[str, str]:
    label_to_key = {plan.label: plan.key for plan in REGION_PLANS}
    label_to_key.update({plan.key: plan.key for plan in REGION_PLANS})
    label_to_key.update({plan.region: plan.key for plan in REGION_PLANS})
    return label_to_key


def _line_region_and_content(line: str, label_to_key: Dict[str, str]) -> Tuple[str, str]:
    content = str(line or "").strip()
    label = ""
    bracket = re.match(r"^\[([^\]]+)\]\s*(.*)$", content)
    if bracket:
        label = bracket.group(1).strip()
        content = bracket.group(2).strip()
    region_match = re.search(r"地区[:：]\s*([^\s，,;；]+)", content)
    if region_match:
        label = region_match.group(1).strip()
    return label_to_key.get(label, ""), content


def huawei_autobuy_server_ids_by_plan(output_lines: Sequence[str]) -> Dict[str, List[str]]:
    """按地区从旧后端输出中提取新创建的 ECS ID。"""
    label_to_key = _region_label_to_key()
    result: Dict[str, List[str]] = {}
    uuid_pattern = r"([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})"
    for raw_line in output_lines:
        line = localize_region_tokens(str(raw_line or ""))
        line_key, content = _line_region_and_content(line, label_to_key)
        if not line_key:
            # 并发购买时“服务器ID列表”可能没有地区前缀，不能用上一条日志的地区承接，
            # 否则会把北京/上海、广州/贵阳的 ECS ID 串到彼此地区，导致后续不上传 ip.txt。
            continue
        if not any(marker in content for marker in ("服务器ID", "云服务器ID", "server_id", "server id", "服务器ID列表")):
            continue
        ids = re.findall(uuid_pattern, content, flags=re.I)
        if not ids:
            continue
        bucket = result.setdefault(line_key, [])
        for server_id in ids:
            if server_id not in bucket:
                bucket.append(server_id)
    return result


def huawei_autobuy_ready_summaries_by_plan(output_lines: Sequence[str]) -> Dict[str, Dict[str, str]]:
    """提取旧购买子进程已经打印完整的“服务器IP + ip.txt”结果，作为云端短反查失败时的兜底。"""
    label_to_key = _region_label_to_key()
    summaries: Dict[str, Dict[str, str]] = {}
    working: Dict[str, Dict[str, str]] = {}
    ip_rows: Dict[str, List[str]] = {}
    reading_ip_key = ""
    for raw_line in output_lines:
        line = localize_region_tokens(str(raw_line or ""))
        line_key, content = _line_region_and_content(line, label_to_key)
        if not line_key:
            continue
        block = working.setdefault(line_key, {})
        if content.startswith("地区:") or content.startswith("地区："):
            block.clear()
            ip_rows.pop(line_key, None)
            reading_ip_key = ""
            continue
        if content.startswith("服务器ID:") or content.startswith("服务器ID："):
            block["server_id"] = content.split(":", 1)[-1].split("：", 1)[-1].strip()
            continue
        if content.startswith("服务器IP:") or content.startswith("服务器IP："):
            block["server_ip"] = content.split(":", 1)[-1].split("：", 1)[-1].strip()
            continue
        if content.startswith("服务器密码:") or content.startswith("服务器密码："):
            block["password"] = content.split(":", 1)[-1].split("：", 1)[-1].strip()
            continue
        if content.startswith("cat > ip.txt"):
            reading_ip_key = line_key
            ip_rows[line_key] = []
            continue
        if reading_ip_key != line_key:
            continue
        if content == "EOF":
            rows = [row for row in ip_rows.get(line_key, []) if row.strip()]
            server_ip = block.get("server_ip", "").strip()
            if rows and server_ip and server_ip.upper() != "N/A":
                block["ip_txt"] = "\n".join(rows) + "\n"
                summaries[line_key] = dict(block)
            reading_ip_key = ""
            continue
        if re.match(r"^(?:eth\d+\s+)?\d+\s+[0-9a-f:]{17}\s+\d{1,3}(?:\.\d{1,3}){3}$", content, flags=re.I):
            ip_rows.setdefault(line_key, []).append(content)
    return summaries
