from huaweicloudsdkcore.auth.credentials import BasicCredentials  # 导入华为云 SDK 的基础鉴权对象。 
from huaweicloudsdkcore.region.region import Region  # 导入区域对象用于设置服务端点。 
from huaweicloudsdkvpc.v2 import VpcClient, CreateSubnetRequest, ListSubnetsRequest  # 导入 VPC 客户端与创建/查询子网请求模型。 
from config import PROJECT_ID, get_runtime_ak_sk  # 导入鉴权参数用于构造客户端。 
from iam_service import get_project_id  # 导入自动获取项目 ID 的函数。 
from data import VPC_ENDPOINT_TEMPLATE  # 导入 VPC 服务端点模板用于拼接请求地址。 
from data import SUBNET_NAME, SUBNET_DESCRIPTION, SUBNET_CIDR, SUBNET_AUTO_REUSE, runtime_resource_name  # 导入子网名称、描述、网段与复用配置。 
from data import SUBNET_GATEWAY_IP, SUBNET_IPV6_ENABLE, SUBNET_DHCP_ENABLE  # 导入子网网关与 DHCP/IPv6 配置。 
from data import SUBNET_PRIMARY_DNS, SUBNET_SECONDARY_DNS, SUBNET_DNS_LIST  # 导入子网 DNS 配置字段。 
from data import SUBNET_AVAILABILITY_ZONE, SUBNET_ENABLE_NETWORK_ADDRESS_USAGE_METRICS  # 导入子网可用区与监控配置。
from data import SUBNET_EXTRA_DHCP_OPTS, SUBNET_TAGS  # 导入子网 DHCP 扩展与标签配置。
from retry_utils import is_transient_cloud_error, retry_cloud_call  # 导入华为云临时网络异常重试工具。
def _resolve_project_id(region_id):  # 根据配置或 IAM 自动解析项目 ID。 
    if PROJECT_ID and PROJECT_ID != "YOUR_PROJECT_ID":  # 若已手工配置项目 ID 则直接使用。 
        return PROJECT_ID  # 返回手工配置的项目 ID。 
    return get_project_id(region_id)  # 否则调用 IAM 接口自动获取项目 ID。 
def _build_vpc_client(region_id):  # 创建 VPC 客户端的函数。 
    project_id = _resolve_project_id(region_id)  # 获取当前区域对应的项目 ID。 
    ak, sk = get_runtime_ak_sk()  # 读取当前线程生效的 AK/SK。 
    creds = BasicCredentials(ak, sk).with_project_id(project_id)  # 使用 AK/SK 与项目 ID 构造鉴权对象。 
    endpoint = VPC_ENDPOINT_TEMPLATE.format(region_id=region_id)  # 根据区域拼接 VPC 服务端点。 
    region = Region(region_id, endpoint)  # 创建区域对象并绑定端点。 
    client = VpcClient.new_builder().with_credentials(creds).with_region(region).build()  # 构建 VPC 客户端实例。 
    return client  # 返回构建好的客户端对象。 
def _find_subnet_by_name(region_id, vpc_id, subnet_name):  # 按名称查找子网的函数。 
    if not subnet_name:  # 若未提供名称则无法判断是否复用。 
        return None  # 直接返回空值表示不复用。 
    client = _build_vpc_client(region_id)  # 构建 VPC 客户端用于查询。 
    request = ListSubnetsRequest(vpc_id=vpc_id)  # 构造子网列表请求并限定 VPC。 
    response = retry_cloud_call("查询子网列表", lambda: client.list_subnets(request))  # 调用 SDK 查询子网列表。
    for subnet in response.subnets or []:  # 遍历子网列表尝试匹配名称。 
        if subnet.name == subnet_name:  # 若名称匹配则认为可复用。 
            return subnet.id  # 返回匹配到的子网 ID。 
    return None  # 未找到匹配项则返回空值。 
def _build_subnet_body(vpc_id, subnet_name):  # 组装子网请求体的函数。 
    if not vpc_id:  # 若未传入 VPC ID 则直接报错。 
        raise ValueError("vpc_id 不能为空")  # 通过异常提醒调用方补齐 VPC ID。 
    subnet_body = {  # 创建子网请求体字典。 
        "name": subnet_name,  # 子网名称字段。 
        "description": SUBNET_DESCRIPTION,  # 子网描述字段。 
        "cidr": SUBNET_CIDR,  # 子网网段字段。 
        "gateway_ip": SUBNET_GATEWAY_IP,  # 子网网关字段。 
        "ipv6_enable": SUBNET_IPV6_ENABLE,  # 是否开启 IPv6 字段。 
        "dhcp_enable": SUBNET_DHCP_ENABLE,  # 是否开启 DHCP 字段。 
        "primary_dns": SUBNET_PRIMARY_DNS,  # 主 DNS 字段。 
        "secondary_dns": SUBNET_SECONDARY_DNS,  # 备 DNS 字段。 
        "dnsList": SUBNET_DNS_LIST,  # DNS 列表字段。 
        "availability_zone": SUBNET_AVAILABILITY_ZONE,  # 可用区字段。 
        "enable_network_address_usage_metrics": SUBNET_ENABLE_NETWORK_ADDRESS_USAGE_METRICS,  # 地址使用率监控字段。 
        "vpc_id": vpc_id,  # 子网所属 VPC ID 字段。 
        "extra_dhcp_opts": SUBNET_EXTRA_DHCP_OPTS,  # DHCP 扩展字段。 
        "tags": SUBNET_TAGS,  # 子网标签字段。 
    }  # 子网请求体初始字典定义结束。 
    filtered_body = {k: v for k, v in subnet_body.items() if v not in (None, "", [], {})}  # 过滤空值字段避免接口报错。 
    return filtered_body  # 返回过滤后的请求体字典。 
def create_subnet(region_id, vpc_id):  # 创建子网的函数实现。 
    subnet_name = runtime_resource_name(SUBNET_NAME)  # 多套资源按编号使用独立子网。
    if SUBNET_AUTO_REUSE:  # 若开启复用则优先查找同名子网。 
        existed_id = _find_subnet_by_name(region_id, vpc_id, subnet_name)  # 按名称查找是否已有子网。 
        if existed_id:  # 若找到则直接返回现有子网 ID。 
            return existed_id  # 复用现有子网避免重复创建。 
    client = _build_vpc_client(region_id)  # 构建 VPC 客户端以调用创建接口。 
    subnet_body = _build_subnet_body(vpc_id, subnet_name)  # 构建子网请求体。 
    request = CreateSubnetRequest()  # 创建子网请求对象。 
    request.body = {"subnet": subnet_body}  # 填充请求体以符合 API 结构要求。 
    # 子网创建如果遇到连接超时，先反查同名子网，避免云端已创建但本地重复创建。
    for attempt in range(1, 4):
        try:
            response = retry_cloud_call("创建子网", lambda: client.create_subnet(request), attempts=1)
            return response.subnet.id  # 返回新建子网的 ID。
        except Exception as exc:
            if not is_transient_cloud_error(exc) or attempt >= 3:
                raise
            existed_id = _find_subnet_by_name(region_id, vpc_id, subnet_name)
            if existed_id:
                return existed_id
            print(f"步骤: 创建子网临时异常，重试 {attempt + 1}/3: {exc}")
    raise RuntimeError("创建子网失败")
