# -*- coding: utf-8 -*-  # 指定文件编码为 UTF-8，确保中文注释不乱码。 
import os  # 导入 os 用于读取环境变量中的 AK/SK。 
import uuid  # 导入 uuid 生成幂等 ClientToken。 
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_subnet(  # 创建子网的统一入口。 
    region: Optional[str],  # 地域，未传则读取默认配置。 
    vpc_id: str,  # VPC ID，必填。 
    zone_id: str,  # 可用区 ID，必填。 
    cidr_block: str,  # 子网网段，必填。 
    subnet_name: Optional[str] = None,  # 子网名称，可选。 
    description: Optional[str] = None,  # 子网描述，可选。 
    ipv6_cidr_block: Optional[int] = None,  # 子网 IPv6 网段末尾 8 位，可选。 
    client_token: Optional[str] = None,  # 幂等 Token，可选。 
    tags: Optional[List[Dict]] = None,  # 标签列表，可选。 
    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 配置", {}  # 返回缺失提示。 
    if not vpc_id:  # 若 VPC ID 为空则返回失败。 
        return False, "VpcId 为空，无法创建子网", {}  # 返回缺失提示。 
    if not zone_id:  # 若可用区为空则返回失败。 
        return False, "ZoneId 为空，无法创建子网", {}  # 返回缺失提示。 
    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 = {  # 构建基础参数，避免传递空字段导致校验失败。 
        "vpc_id": vpc_id,  # 设置 VPC ID。 
        "zone_id": zone_id,  # 设置可用区 ID。 
        "cidr_block": cidr_block,  # 设置子网网段。 
        "client_token": token_value,  # 设置幂等 Token。 
    }  # 基础参数构建结束。 
    name_value = _normalize(subnet_name)  # 清理子网名称空格。 
    if name_value:  # 仅在名称非空时传入。 
        params["subnet_name"] = name_value  # 写入子网名称。 
    desc_value = _normalize(description)  # 清理子网描述空格。 
    if desc_value:  # 仅在描述非空时传入。 
        params["description"] = desc_value  # 写入子网描述。 
    if ipv6_cidr_block is not None:  # 仅在 IPv6 值不为空时传入。 
        params["ipv6_cidr_block"] = ipv6_cidr_block  # 写入 IPv6 网段末尾 8 位。 
    if tags:  # 仅在标签列表非空时传入。 
        params["tags"] = tags  # 写入标签列表。 
    request = volcenginesdkvpc.CreateSubnetRequest(**params)  # 使用整理后的参数构建请求对象。 
    try:  # 捕获 SDK 调用异常。 
        response = api_instance.create_subnet(request)  # 调用创建子网接口。 
    except ApiException as exc:  # 捕获火山 SDK 抛出的异常。 
        return False, f"创建子网失败: {exc}", {}  # 返回失败状态与错误信息。 
    data_dict = _to_dict(response)  # 将响应对象转换为字典。 
    return True, "创建子网成功", data_dict  # 返回成功状态与结果。 

def create_default_subnet(  # 按默认配置创建子网。 
    region: Optional[str],  # 地域，未传则读取默认配置。 
    vpc_id: str,  # VPC ID。 
    group_index: int = 1,  # 资源命名分组，1 或 2。 
) -> Tuple[bool, str, Dict]:  # 返回创建结果。 
    region_value = _resolve_region(region)  # 解析地域，用于选择可用区。 
    zone_id = data.SUBNET_ZONE_MAP.get(region_value, "")  # 从映射表获取默认可用区。 
    subnet_name = data.SUBNET_NAME_GROUP_2 if group_index == 2 else data.SUBNET_NAME_GROUP_1  # 根据分组选择子网名称。 
    return create_subnet(  # 调用通用创建方法。 
        region=region_value,  # 传入地域或使用默认值。 
        vpc_id=vpc_id,  # 传入 VPC ID。 
        zone_id=zone_id,  # 传入默认可用区 ID。 
        cidr_block=data.SUBNET_CIDR,  # 使用默认子网网段。 
        subnet_name=subnet_name,  # 使用分组对应的子网名称。 
        description=data.SUBNET_DESCRIPTION,  # 使用默认描述。 
        ipv6_cidr_block=data.SUBNET_IPV6_LAST8,  # 默认 IPv6 末尾 8 位。 
    )  # 返回创建结果。 

def find_subnet_by_name(  # 按名称与 VPC 查询子网。 
    region: Optional[str],  # 地域，未传则读取默认配置。 
    subnet_name: str,  # 子网名称。 
    vpc_id: str = "",  # VPC ID，可选但建议传入以避免同名误匹配。 
    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 的最终来源。 
    name_value = _normalize(subnet_name)  # 清理子网名称。 
    vpc_value = _normalize(vpc_id)  # 清理 VPC ID。 
    if not ak_value or not sk_value:  # 若 AK/SK 为空则返回失败。 
        return False, "AK/SK 为空，无法查询子网", {}  # 返回缺失提示。 
    if not region_value:  # 若 region 为空则返回失败。 
        return False, "地域为空，无法查询子网", {}  # 返回缺失提示。 
    if not name_value:  # 若子网名称为空则返回失败。 
        return False, "SubnetName 为空，无法查询子网", {}  # 返回缺失提示。 
    configuration = _build_configuration(ak_value, sk_value, region_value)  # 构建 SDK 配置对象。 
    volcenginesdkcore.Configuration.set_default(configuration)  # 设置 SDK 默认配置供后续调用。 
    api_instance = volcenginesdkvpc.VPCApi()  # 创建 VPC API 实例。 
    try:  # 尝试使用名称与 VPC 过滤。 
        params = {"subnet_names": [name_value]}  # 构建查询参数。 
        if vpc_value:  # 仅在 VPC ID 存在时加入过滤。 
            params["vpc_id"] = vpc_value  # 加入 VPC ID 过滤。 
        request = volcenginesdkvpc.DescribeSubnetsRequest(**params)  # 构建请求对象。 
    except TypeError:  # 捕获参数不匹配时降级为全量查询。 
        request = volcenginesdkvpc.DescribeSubnetsRequest()  # 无过滤参数的请求对象。 
    try:  # 捕获 SDK 调用异常。 
        response = api_instance.describe_subnets(request)  # 调用查询子网接口。 
    except ApiException as exc:  # 捕获火山 SDK 抛出的异常。 
        return False, f"查询子网失败: {exc}", {}  # 返回失败状态与错误信息。 
    data_dict = _to_dict(response)  # 将响应对象转换为字典。 
    result = data_dict.get("Result") or data_dict.get("result") or data_dict  # 兼容不同响应结构。 
    subnet_list = result.get("Subnets") or result.get("subnets") or result.get("SubnetSet") or []  # 提取子网列表。 
    for item in subnet_list:  # 遍历子网列表查找目标名称。 
        item_name = item.get("SubnetName") or item.get("subnet_name") or ""  # 提取子网名称。 
        if item_name != name_value:  # 非目标名称则跳过。 
            continue  # 跳过当前条目。 
        item_vpc_id = item.get("VpcId") or item.get("vpc_id") or ""  # 提取 VPC ID。 
        if vpc_value and item_vpc_id and item_vpc_id != vpc_value:  # VPC 不匹配则跳过。 
            continue  # 跳过其他 VPC 下的同名子网。 
        status = str(item.get("Status") or item.get("status") or "")  # 读取子网状态。 
        if status.lower() == "deleted":  # 跳过已删除资源。 
            continue  # 跳过已删除状态。 
        return True, "找到子网", item  # 返回目标子网信息。 
    return False, "未找到目标子网", {}  # 未找到目标子网时返回失败。 
