# -*- coding: utf-8 -*-  # 指定文件编码为 UTF-8，确保中文注释不乱码。 
import os  # 导入 os 用于读取环境变量中的 AK/SK。 
import uuid  # 导入 uuid 生成幂等 ClientToken。 
import time  # 导入 time 用于等待 VPC 状态就绪。 
from typing import Dict, Tuple, Optional, List  # 导入类型标注便于阅读与提示。 
import volcenginesdkcore  # 导入火山引擎 SDK Core 以配置 AK/SK。 
import volcenginesdkvpc  # 导入火山引擎 VPC SDK 调用创建接口。 
from volcenginesdkcore.rest import ApiException  # 导入 SDK 异常类型用于捕获接口错误。 
from volcengine import config, data  # 导入配置与数据参数。 

def _normalize(value: Optional[str]) -> str:  # 统一处理字符串输入，避免空值异常。 
    return (value or "").strip()  # 返回去除空格后的字符串。 

def _resolve_credentials(ak: Optional[str], sk: Optional[str]) -> Tuple[str, str]:  # 解析 AK/SK 来源。 
    ak_value = _normalize(ak)  # 清理传入 AK 的空格。 
    sk_value = _normalize(sk)  # 清理传入 SK 的空格。 
    if ak_value and sk_value:  # 若调用方已传入 AK/SK 则直接使用。 
        return ak_value, sk_value  # 返回传入的 AK/SK。 
    env_ak = _normalize(os.getenv("VOLC_AK"))  # 尝试从环境变量读取 AK。 
    env_sk = _normalize(os.getenv("VOLC_SK"))  # 尝试从环境变量读取 SK。 
    if env_ak and env_sk:  # 若环境变量存在则使用。 
        return env_ak, env_sk  # 返回环境变量中的 AK/SK。 
    cfg_ak = _normalize(getattr(config, "DEFAULT_ACCESS_KEY", ""))  # 读取配置文件中的默认 AK。 
    cfg_sk = _normalize(getattr(config, "DEFAULT_SECRET_KEY", ""))  # 读取配置文件中的默认 SK。 
    return cfg_ak, cfg_sk  # 返回配置文件中的默认 AK/SK（可能为空）。 

def _resolve_region(region: Optional[str]) -> str:  # 解析地域参数来源。 
    region_value = _normalize(region)  # 清理传入 region 的空格。 
    if region_value:  # 若调用方传入 region 则使用。 
        return region_value  # 返回传入 region。 
    return _normalize(getattr(config, "DEFAULT_REGION", ""))  # 否则使用配置文件默认地域。 

def _build_configuration(ak: str, sk: str, region: str) -> volcenginesdkcore.Configuration:  # 构建 SDK 配置对象。 
    configuration = volcenginesdkcore.Configuration()  # 创建 SDK 配置实例。 
    configuration.ak = ak  # 设置 Access Key。 
    configuration.sk = sk  # 设置 Secret Key。 
    configuration.region = region  # 设置请求地域。 
    return configuration  # 返回配置对象供调用方使用。 

def _to_dict(obj) -> Dict:  # 将 SDK 返回对象安全转换为字典。 
    if obj is None:  # 判断对象是否为空。 
        return {}  # 为空时返回空字典。 
    if isinstance(obj, dict):  # 如果已经是字典直接返回。 
        return obj  # 返回字典本身。 
    to_dict = getattr(obj, "to_dict", None)  # 尝试读取对象的 to_dict 方法。 
    if callable(to_dict):  # 如果 to_dict 可调用则执行转换。 
        return to_dict()  # 返回转换后的字典。 
    return {}  # 默认返回空字典避免崩溃。 

def create_vpc(  # 创建 VPC 的统一入口。 
    region: Optional[str],  # 地域，未传则读取默认配置。 
    cidr_block: str,  # IPv4 网段，必填。 
    vpc_name: Optional[str] = None,  # VPC 名称，可选。 
    description: Optional[str] = None,  # VPC 描述，可选。 
    enable_ipv6: bool = False,  # 是否开启 IPv6。 
    ipv6_cidr_block: Optional[str] = None,  # IPv6 网段，可选。 
    dns_servers: Optional[List[str]] = None,  # DNS 列表，可选。 
    project_name: Optional[str] = None,  # 项目名称，可选。 
    client_token: Optional[str] = None,  # 幂等 Token，可选。 
    ak: Optional[str] = None,  # AK，可选，优先级高。 
    sk: Optional[str] = None,  # SK，可选，优先级高。 
) -> Tuple[bool, str, Dict]:  # 返回调用状态与结果数据。 
    ak_value, sk_value = _resolve_credentials(ak, sk)  # 解析 AK/SK 的最终来源。 
    region_value = _resolve_region(region)  # 解析 region 的最终来源。 
    if not ak_value or not sk_value:  # 若 AK/SK 为空则返回失败。 
        return False, "AK/SK 为空，请通过网页传入或在 config.py 配置", {}  # 返回缺失提示。 
    if not region_value:  # 若 region 为空则返回失败。 
        return False, "地域为空，请通过网页传入或在 config.py 配置", {}  # 返回缺失提示。 
    configuration = _build_configuration(ak_value, sk_value, region_value)  # 构建 SDK 配置对象。 
    volcenginesdkcore.Configuration.set_default(configuration)  # 设置 SDK 默认配置供后续调用。 
    api_instance = volcenginesdkvpc.VPCApi()  # 创建 VPC API 实例。 
    token_value = client_token or str(uuid.uuid4())  # 生成幂等 Token，避免重复创建。 
    params = {  # 构建基础参数，避免传递空字段导致校验失败。 
        "cidr_block": cidr_block,  # 设置 VPC IPv4 网段。 
        "client_token": token_value,  # 设置幂等 Token。 
    }  # 基础参数构建结束。 
    name_value = _normalize(vpc_name)  # 清理 VPC 名称空格。 
    if name_value:  # 仅在名称非空时传入。 
        params["vpc_name"] = name_value  # 写入 VPC 名称参数。 
    desc_value = _normalize(description)  # 清理 VPC 描述空格。 
    if desc_value:  # 仅在描述非空时传入。 
        params["description"] = desc_value  # 写入 VPC 描述参数。 
    if enable_ipv6:  # 仅在明确开启 IPv6 时传入相关字段。 
        params["enable_ipv6"] = True  # 写入 IPv6 开关。 
        ipv6_value = _normalize(ipv6_cidr_block)  # 清理 IPv6 网段。 
        if ipv6_value:  # 仅在 IPv6 网段非空时传入。 
            params["ipv6_cidr_block"] = ipv6_value  # 写入 IPv6 网段参数。 
    dns_list = dns_servers or []  # 归一化 DNS 列表为空列表。 
    if dns_list:  # 仅在 DNS 列表非空时传入。 
        params["dns_servers"] = dns_list  # 写入 DNS 服务器列表。 
    project_value = _normalize(project_name)  # 清理项目名称空格。 
    if project_value:  # 仅在项目名称非空时传入。 
        params["project_name"] = project_value  # 写入项目名称参数。 
    request = volcenginesdkvpc.CreateVpcRequest(**params)  # 使用整理后的参数构建请求对象。 
    try:  # 捕获 SDK 调用异常。 
        response = api_instance.create_vpc(request)  # 调用创建 VPC 接口。 
    except ApiException as exc:  # 捕获火山 SDK 抛出的异常。 
        return False, f"创建 VPC 失败: {exc}", {}  # 返回失败状态与错误信息。 
    data_dict = _to_dict(response)  # 将响应对象转换为字典。 
    return True, "创建 VPC 成功", data_dict  # 返回成功状态与结果。 

def create_default_vpc(  # 按默认配置创建 VPC。 
    region: Optional[str] = None,  # 地域参数。 
    group_index: int = 1,  # 资源命名分组，1 或 2。 
) -> Tuple[bool, str, Dict]:  # 返回创建结果。 
    vpc_name = data.VPC_NAME_GROUP_2 if group_index == 2 else data.VPC_NAME_GROUP_1  # 根据分组选择名称。 
    return create_vpc(  # 调用通用创建方法。 
        region=region,  # 传入地域或使用默认值。 
        cidr_block=data.VPC_CIDR,  # 使用默认 IPv4 网段。 
        vpc_name=vpc_name,  # 使用分组对应的 VPC 名称。 
        description=data.VPC_DESCRIPTION,  # 使用默认描述。 
        enable_ipv6=data.VPC_ENABLE_IPV6,  # 使用默认 IPv6 开关。 
        ipv6_cidr_block=data.VPC_IPV6_CIDR,  # 使用默认 IPv6 网段。 
        dns_servers=data.VPC_DNS_SERVERS,  # 使用默认 DNS 列表。 
        project_name=data.VPC_PROJECT_NAME,  # 使用默认项目名称。 
    )  # 返回创建结果。 

def find_vpc_by_name(  # 按名称查询 VPC。 
    region: Optional[str],  # 地域，未传则读取默认配置。 
    vpc_name: str,  # VPC 名称。 
    ak: Optional[str] = None,  # AK，可选，优先级高。 
    sk: Optional[str] = None,  # SK，可选，优先级高。 
) -> Tuple[bool, str, Dict]:  # 返回状态、提示与 VPC 信息。 
    ak_value, sk_value = _resolve_credentials(ak, sk)  # 解析 AK/SK 的最终来源。 
    region_value = _resolve_region(region)  # 解析 region 的最终来源。 
    name_value = _normalize(vpc_name)  # 清理 VPC 名称。 
    if not ak_value or not sk_value:  # 若 AK/SK 为空则返回失败。 
        return False, "AK/SK 为空，无法查询 VPC", {}  # 返回缺失提示。 
    if not region_value:  # 若 region 为空则返回失败。 
        return False, "地域为空，无法查询 VPC", {}  # 返回缺失提示。 
    if not name_value:  # 若 VPC 名称为空则返回失败。 
        return False, "VpcName 为空，无法查询 VPC", {}  # 返回缺失提示。 
    configuration = _build_configuration(ak_value, sk_value, region_value)  # 构建 SDK 配置对象。 
    volcenginesdkcore.Configuration.set_default(configuration)  # 设置 SDK 默认配置供后续调用。 
    api_instance = volcenginesdkvpc.VPCApi()  # 创建 VPC API 实例。 
    try:  # 尝试使用名称过滤。 
        request = volcenginesdkvpc.DescribeVpcsRequest(vpc_names=[name_value])  # 构建请求对象。 
    except TypeError:  # 捕获参数不匹配时降级为全量查询。 
        request = volcenginesdkvpc.DescribeVpcsRequest()  # 无过滤参数的请求对象。 
    try:  # 捕获 SDK 调用异常。 
        response = api_instance.describe_vpcs(request)  # 调用查询 VPC 接口。 
    except ApiException as exc:  # 捕获火山 SDK 抛出的异常。 
        return False, f"查询 VPC 失败: {exc}", {}  # 返回失败状态与错误信息。 
    data_dict = _to_dict(response)  # 将响应对象转换为字典。 
    result = data_dict.get("Result") or data_dict.get("result") or data_dict  # 兼容不同响应结构。 
    vpc_list = result.get("Vpcs") or result.get("vpcs") or result.get("VpcSet") or []  # 提取 VPC 列表。 
    for item in vpc_list:  # 遍历 VPC 列表查找目标名称。 
        item_name = item.get("VpcName") or item.get("vpc_name") or ""  # 提取 VPC 名称。 
        if item_name != name_value:  # 非目标名称则跳过。 
            continue  # 跳过当前条目。 
        status = str(item.get("Status") or item.get("status") or "")  # 读取 VPC 状态。 
        if status.lower() == "deleted":  # 跳过已删除资源。 
            continue  # 跳过已删除状态。 
        return True, "找到 VPC", item  # 返回目标 VPC 信息。 
    return False, "未找到目标 VPC", {}  # 未找到目标 VPC 时返回失败。 

def describe_vpc_status(  # 查询 VPC 状态的统一入口。 
    region: Optional[str],  # 地域，未传则读取默认配置。 
    vpc_id: str,  # 目标 VPC ID。 
    ak: Optional[str] = None,  # AK，可选，优先级高。 
    sk: Optional[str] = None,  # SK，可选，优先级高。 
) -> Tuple[bool, str, str]:  # 返回调用状态与 VPC 状态字符串。 
    ak_value, sk_value = _resolve_credentials(ak, sk)  # 解析 AK/SK 的最终来源。 
    region_value = _resolve_region(region)  # 解析 region 的最终来源。 
    if not ak_value or not sk_value:  # 若 AK/SK 为空则返回失败。 
        return False, "AK/SK 为空，无法查询 VPC 状态", ""  # 返回缺失提示。 
    if not region_value:  # 若 region 为空则返回失败。 
        return False, "地域为空，无法查询 VPC 状态", ""  # 返回缺失提示。 
    if not vpc_id:  # 若 VPC ID 为空则返回失败。 
        return False, "VpcId 为空，无法查询 VPC 状态", ""  # 返回缺失提示。 
    configuration = _build_configuration(ak_value, sk_value, region_value)  # 构建 SDK 配置对象。 
    volcenginesdkcore.Configuration.set_default(configuration)  # 设置 SDK 默认配置供后续调用。 
    api_instance = volcenginesdkvpc.VPCApi()  # 创建 VPC API 实例。 
    request = None  # 预置请求对象，后续按参数构建。 
    try:  # 尝试使用 vpc_ids 过滤。 
        request = volcenginesdkvpc.DescribeVpcsRequest(vpc_ids=[vpc_id])  # 构建带过滤条件的请求。 
    except TypeError:  # 捕获参数名不匹配情况。 
        request = volcenginesdkvpc.DescribeVpcsRequest()  # 降级为无过滤参数。 
    try:  # 捕获 SDK 调用异常。 
        response = api_instance.describe_vpcs(request)  # 调用查询 VPC 接口。 
    except ApiException as exc:  # 捕获火山 SDK 抛出的异常。 
        return False, f"查询 VPC 状态失败: {exc}", ""  # 返回失败状态与错误信息。 
    data_dict = _to_dict(response)  # 将响应对象转换为字典。 
    result = data_dict.get("Result") or data_dict.get("result") or data_dict  # 兼容不同响应结构。 
    vpc_list = result.get("Vpcs") or result.get("vpcs") or result.get("VpcSet") or []  # 提取 VPC 列表。 
    for item in vpc_list:  # 遍历 VPC 列表查找目标 VPC。 
        item_id = item.get("VpcId") or item.get("vpc_id")  # 提取 VPC ID。 
        if item_id != vpc_id:  # 若非目标 VPC 则跳过。 
            continue  # 跳过当前条目。 
        status = item.get("Status") or item.get("status") or ""  # 提取 VPC 状态。 
        return True, "查询 VPC 状态成功", str(status)  # 返回状态字符串。 
    return False, "未找到目标 VPC", ""  # 未找到目标 VPC 时返回失败。 

def wait_for_vpc_available(  # 等待 VPC 状态就绪。 
    region: Optional[str],  # 地域，未传则读取默认配置。 
    vpc_id: str,  # 目标 VPC ID。 
    timeout_seconds: int = 120,  # 最大等待时间（秒）。 
    interval_seconds: int = 5,  # 轮询间隔（秒）。 
    ak: Optional[str] = None,  # AK，可选，优先级高。 
    sk: Optional[str] = None,  # SK，可选，优先级高。 
) -> Tuple[bool, str]:  # 返回等待结果与提示信息。 
    deadline = time.monotonic() + timeout_seconds  # 计算超时截止时间。 
    while time.monotonic() < deadline:  # 循环等待直至超时。 
        ok, message, status = describe_vpc_status(region, vpc_id, ak, sk)  # 查询 VPC 当前状态。 
        if ok and status:  # 若查询成功且有状态值。 
            normalized = status.strip().lower()  # 统一状态字符串大小写。 
            if normalized in {"available", "active", "ok", "running"}:  # 判断是否已就绪。 
                return True, "VPC 状态就绪"  # 返回就绪结果。 
        time.sleep(interval_seconds)  # 未就绪则等待后继续轮询。 
    return False, f"等待 VPC 就绪超时({timeout_seconds}s)"  # 超时后返回失败。 
