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

try:
    from common.debug_billing import is_on_demand_debug_enabled
except Exception:
    def is_on_demand_debug_enabled(_cloud: str) -> bool:
        return False

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 _format_api_exception(exc: ApiException) -> str:  # 格式化 SDK 异常，保留服务端返回体。 
    parts = []  # 收集异常字段。 
    status = getattr(exc, "status", None)  # HTTP 状态码。 
    reason = getattr(exc, "reason", None)  # HTTP 原因。 
    body = getattr(exc, "body", None)  # 服务端响应体。 
    headers = getattr(exc, "headers", None)  # 响应头，可能含 request id。 
    if status: 
        parts.append(f"status={status}") 
    if reason: 
        parts.append(f"reason={reason}") 
    if body: 
        parts.append(f"body={body}") 
    if headers: 
        request_id = "" 
        try: 
            request_id = headers.get("X-Tt-Logid") or headers.get("X-Request-Id") or headers.get("Request-Id") 
        except AttributeError: 
            request_id = "" 
        if request_id: 
            parts.append(f"request_id={request_id}") 
    if parts: 
        return "; ".join(parts) 
    return str(exc) 

def _is_retryable_api_exception(exc: ApiException) -> bool:  # 判断是否可重试的服务端异常。 
    try: 
        status = int(getattr(exc, "status", 0) or 0) 
    except (TypeError, ValueError): 
        status = 0 
    if status >= 500: 
        return True 
    text = _format_api_exception(exc).lower() 
    return "internalerror" in text or "serviceunavailable" in text or "throttl" in text or "timeout" in text 

def find_instance_by_name(  # 按名称查询实例。 
    region: Optional[str],  # 地域，未传则读取默认配置。 
    instance_name: str,  # 实例名称。 
    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(instance_name)  # 清理实例名称。 
    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, "InstanceName 为空，无法查询实例", {}  # 返回缺失提示。 
    configuration = _build_configuration(ak_value, sk_value, region_value)  # 构建 SDK 配置对象。 
    volcenginesdkcore.Configuration.set_default(configuration)  # 设置 SDK 默认配置供后续调用。 
    api_instance = volcenginesdkecs.ECSApi()  # 创建 ECS API 实例。 
    try:  # 尝试使用名称过滤。 
        request = volcenginesdkecs.DescribeInstancesRequest(instance_name=name_value)  # 构建请求对象。 
    except TypeError:  # 捕获参数不匹配时降级为全量查询。 
        request = volcenginesdkecs.DescribeInstancesRequest()  # 无过滤参数的请求对象。 
    try:  # 捕获 SDK 调用异常。 
        response = api_instance.describe_instances(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  # 兼容不同响应结构。 
    inst_list = result.get("Instances") or result.get("instances") or []  # 提取实例列表。 
    for item in inst_list:  # 遍历实例列表查找目标名称。 
        item_name = item.get("InstanceName") or item.get("instance_name") or ""  # 提取实例名称。 
        if item_name != name_value:  # 非目标名称则跳过。 
            continue  # 跳过当前条目。 
        status = str(item.get("Status") or item.get("status") or "")  # 读取实例状态。 
        if status.lower() == "deleted":  # 跳过已删除资源。 
            continue  # 跳过已删除状态。 
        return True, "找到实例", item  # 返回实例信息。 
    return False, "未找到目标实例", {}  # 未找到目标实例时返回失败。 

def _request(cls, **kwargs):  # 兼容不同 SDK 版本的请求构造。 
    try: 
        return cls(**kwargs) 
    except TypeError: 
        request = cls() 
        for key, value in kwargs.items(): 
            try: 
                setattr(request, key, value) 
            except Exception: 
                pass 
        return request 

def _extract_instance_list(data: Dict) -> List[Dict]:  # 从 DescribeInstances 响应中提取实例列表。 
    result = data.get("Result") or data.get("result") or data 
    direct = ( 
        result.get("Instances") 
        or result.get("instances") 
        or result.get("InstanceSet") 
        or result.get("instance_set") 
    ) 
    if isinstance(direct, list): 
        return [item for item in direct if isinstance(item, dict)] 

    def walk(value) -> List[Dict]: 
        if isinstance(value, dict): 
            for key, item in value.items(): 
                if key.lower() in {"instances", "instanceset", "instance_set"} and isinstance(item, list): 
                    return [entry for entry in item if isinstance(entry, dict)] 
            for item in value.values(): 
                found = walk(item) 
                if found: 
                    return found 
        elif isinstance(value, list): 
            dict_items = [entry for entry in value if isinstance(entry, dict)] 
            if dict_items and any(entry.get("InstanceId") or entry.get("instance_id") for entry in dict_items): 
                return dict_items 
            for item in value: 
                found = walk(item) 
                if found: 
                    return found 
        return [] 

    return walk(data) 

def _field(item: Dict, *keys: str) -> str:  # 提取字段，兼容原始响应嵌套。 
    for key in keys: 
        value = item.get(key) 
        if value not in (None, ""): 
            return str(value).strip() 
    raw = item.get("_raw") 
    if isinstance(raw, dict): 
        for key in keys: 
            value = raw.get(key) 
            if value not in (None, ""): 
                return str(value).strip() 
    return "" 

def _collect_values_by_key(value, key_names: set) -> List[str]:  # 递归收集指定键名的字符串值。 
    found: List[str] = [] 
    if isinstance(value, dict): 
        for key, item in value.items(): 
            if key.lower() in key_names: 
                if isinstance(item, list): 
                    found.extend(str(entry).strip() for entry in item if entry not in (None, "")) 
                elif item not in (None, ""): 
                    found.append(str(item).strip()) 
            found.extend(_collect_values_by_key(item, key_names)) 
    elif isinstance(value, list): 
        for item in value: 
            found.extend(_collect_values_by_key(item, key_names)) 
    return [item for item in found if item] 

def _private_ips_from_instance(instance: Dict) -> List[str]:  # 从实例/网卡结构中收集私网 IP。 
    keys = { 
        "privateipaddress", 
        "private_ip_address", 
        "primaryipaddress", 
        "primary_ip_address", 
        "privateip", 
        "private_ip", 
    } 
    return _collect_values_by_key(instance, keys) 

def _subnet_ids_from_instance(instance: Dict) -> List[str]:  # 从实例/网卡结构中收集子网 ID。 
    return _collect_values_by_key(instance, {"subnetid", "subnet_id"}) 

def _vpc_ids_from_instance(instance: Dict) -> List[str]:  # 从实例/网卡结构中收集 VPC ID。 
    return _collect_values_by_key(instance, {"vpcid", "vpc_id"}) 

def find_instance_by_private_ip(  # 按 VPC/子网/私网 IP 查找已有实例，避免只依赖名称。 
    region: Optional[str], 
    vpc_id: str, 
    subnet_id: str, 
    private_ip: str, 
    ak: Optional[str] = None, 
    sk: Optional[str] = None, 
) -> Tuple[bool, str, Dict]: 
    ak_value, sk_value = _resolve_credentials(ak, sk) 
    region_value = _resolve_region(region) 
    target_ip = _normalize(private_ip) 
    if not ak_value or not sk_value: 
        return False, "AK/SK 为空，无法按私网 IP 查询实例", {} 
    if not region_value or not target_ip: 
        return False, "地域或私网 IP 为空，无法按私网 IP 查询实例", {} 
    configuration = _build_configuration(ak_value, sk_value, region_value) 
    volcenginesdkcore.Configuration.set_default(configuration) 
    api_instance = volcenginesdkecs.ECSApi() 
    last_error = "" 
    candidates: List[Dict] = [] 
    for page in range(1, 21): 
        request = _request(volcenginesdkecs.DescribeInstancesRequest, page_number=page, page_size=100) 
        try: 
            response = api_instance.describe_instances(request) 
        except ApiException as exc: 
            last_error = f"查询实例失败: {_format_api_exception(exc)}" 
            break 
        data_dict = _to_dict(response) 
        items = _extract_instance_list(data_dict) 
        if not items: 
            break 
        candidates.extend(items) 
        result = data_dict.get("Result") or data_dict.get("result") or data_dict 
        total = result.get("TotalCount") or result.get("total_count") or result.get("Total") 
        try: 
            if int(total) <= len(candidates): 
                break 
        except (TypeError, ValueError): 
            pass 
    if last_error and not candidates: 
        return False, last_error, {} 
    network_fallback: Dict = {} 
    for item in candidates: 
        status = str(item.get("Status") or item.get("status") or "").lower() 
        if status == "deleted": 
            continue 
        private_ips = set(_private_ips_from_instance(item)) 
        item_vpcs = set(_vpc_ids_from_instance(item)) 
        item_subnets = set(_subnet_ids_from_instance(item)) 
        network_matches = True 
        if vpc_id and item_vpcs and vpc_id not in item_vpcs: 
            network_matches = False 
        if subnet_id and item_subnets and subnet_id not in item_subnets: 
            network_matches = False 
        if network_matches and not network_fallback: 
            network_fallback = item 
        if target_ip not in private_ips: 
            continue 
        if not network_matches: 
            continue 
        return True, "按私网 IP 找到实例", item 
    if network_fallback: 
        return True, "按VPC/子网找到实例，私网IP字段未完整返回", network_fallback 
    return False, "未找到占用该私网 IP 的实例", {} 

def run_instances(  # 创建 ECS 实例的统一入口。 
    region: Optional[str],  # 地域，未传则读取默认配置。 
    subnet_id: str,  # 子网 ID，必填。 
    security_group_id: str,  # 安全组 ID，必填。 
    instance_name: str,  # 实例名称，必填。 
    image_id: str,  # 镜像 ID，必填。 
    instance_type_id: str,  # 实例规格，必填。 
    password: str,  # 实例登录密码，必填。 
    zone_id: str,  # 可用区 ID，必填。 
    primary_ip: str,  # 主网卡固定 IP。 
    primary_extra_ips: Optional[List[str]] = None,  # 主网卡附加 IP 列表。 
    secondary_ip: Optional[str] = None,  # 副网卡固定 IP。 
    secondary_extra_ips: Optional[List[str]] = None,  # 副网卡附加 IP 列表。 
    system_disk_size: Optional[int] = None,  # 系统盘大小。 
    system_disk_type: Optional[str] = None,  # 系统盘类型。 
    charge_type: Optional[str] = None,  # 计费方式。 
    count: Optional[int] = None,  # 创建数量。 
    client_token: Optional[str] = None,  # 幂等 Token。 
    project_name: Optional[str] = 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 subnet_id:  # 判断子网 ID 是否为空。 
        return False, "SubnetId 为空，无法创建实例", {}  # 返回缺失提示。 
    if not security_group_id:  # 判断安全组 ID 是否为空。 
        return False, "SecurityGroupId 为空，无法创建实例", {}  # 返回缺失提示。 
    if not image_id:  # 判断镜像 ID 是否为空。 
        return False, "ImageId 为空，无法创建实例", {}  # 返回缺失提示。 
    if not instance_type_id:  # 判断规格是否为空。 
        return False, "InstanceTypeId 为空，无法创建实例", {}  # 返回缺失提示。 
    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 = volcenginesdkecs.ECSApi()  # 创建 ECS API 实例。 
    token_value = client_token or str(uuid.uuid4())  # 生成幂等 Token，避免重复创建。 
    nic_list = []  # 初始化网卡列表用于构建请求。 
    primary_nic = volcenginesdkecs.NetworkInterfaceForRunInstancesInput(  # 构建主网卡参数。 
        subnet_id=subnet_id,  # 设置主网卡所属子网。 
        security_group_ids=[security_group_id],  # 绑定安全组到主网卡。 
        primary_ip_address=primary_ip,  # 仅绑定主 IP，附加 IP 由后续流程分配。 
    )  # 主网卡参数构建结束。 
    nic_list.append(primary_nic)  # 将主网卡加入网卡列表。 
    if secondary_ip:  # 判断是否需要添加副网卡。 
        secondary_nic = volcenginesdkecs.NetworkInterfaceForRunInstancesInput(  # 构建副网卡参数。 
            subnet_id=subnet_id,  # 设置副网卡所属子网。 
            security_group_ids=[security_group_id],  # 绑定安全组到副网卡。 
            primary_ip_address=secondary_ip,  # 仅绑定主 IP，附加 IP 由后续流程分配。 
        )  # 副网卡参数构建结束。 
        nic_list.append(secondary_nic)  # 将副网卡加入网卡列表。 
    volumes = []  # 初始化磁盘列表用于构建请求。 
    if system_disk_size and system_disk_type:  # 仅在系统盘参数齐全时构建。 
        system_volume = volcenginesdkecs.VolumeForRunInstancesInput(  # 构建系统盘参数。 
            size=system_disk_size,  # 设置系统盘大小。 
            volume_type=system_disk_type,  # 设置系统盘类型。 
            delete_with_instance="true",  # 使用字符串 true 以匹配 SDK 字段类型。 
        )  # 系统盘参数构建结束。 
        volumes.append(system_volume)  # 将系统盘加入磁盘列表。 
    effective_charge_type = "PostPaid" if is_on_demand_debug_enabled("volc") else (charge_type or "PostPaid")
    params = {  # 构建创建实例的核心参数集合。 
        "client_token": token_value,  # 设置幂等 Token。 
        "count": count or 1,  # 设置创建数量。 
        "image_id": image_id,  # 设置镜像 ID。 
        "instance_name": instance_name,  # 设置实例名称。 
        "instance_type_id": instance_type_id,  # 设置实例规格。 
        "instance_charge_type": effective_charge_type,  # 设置计费方式。 
        "password": password,  # 设置登录密码。 
        "zone_id": zone_id,  # 设置实例可用区。 
        "network_interfaces": nic_list,  # 设置网卡列表。 
        "volumes": volumes,  # 设置系统盘配置。 
    }  # 核心参数构建结束。 
    if params["instance_charge_type"] == "PrePaid":  # 当使用包年包月计费时附加续费参数。 
        prepaid_cfg = getattr(data, "ECS_PREPAID", {}) or {}  # 读取包年包月配置。 
        period = prepaid_cfg.get("Period")  # 购买时长（月）。 
        period_unit = prepaid_cfg.get("PeriodUnit")  # 购买时长单位。 
        auto_renew = prepaid_cfg.get("AutoRenew")  # 是否自动续费。 
        auto_renew_period = prepaid_cfg.get("AutoRenewPeriod")  # 自动续费时长。 
        if period:  # 仅在配置存在时写入。 
            params["period"] = period  # 设置购买时长。 
        if period_unit:  # 仅在配置存在时写入。 
            params["period_unit"] = period_unit  # 设置购买时长单位。 
        if auto_renew is not None:  # 允许 False 显式关闭。 
            params["auto_renew"] = auto_renew  # 设置是否自动续费。 
        if auto_renew_period:  # 仅在配置存在时写入。 
            params["auto_renew_period"] = auto_renew_period  # 设置自动续费时长。 
    project_value = _normalize(project_name)  # 清理项目名称空格。 
    if project_value:  # 仅在项目名称非空时传入。 
        params["project_name"] = project_value  # 写入项目名称参数。 
    request = volcenginesdkecs.RunInstancesRequest(**params)  # 使用整理后的参数构建请求对象。 
    last_error = ""  # 保存最后一次失败信息。 
    for attempt in range(1, 4):  # ECS 创建 5xx/限流错误做短重试。 
        try:  # 捕获 SDK 调用异常。 
            response = api_instance.run_instances(request)  # 调用创建实例接口。 
            data_dict = _to_dict(response)  # 将响应对象转换为字典。 
            return True, "创建实例成功", data_dict  # 返回成功状态与结果。 
        except ApiException as exc:  # 捕获火山 SDK 抛出的异常。 
            detail = _format_api_exception(exc)  # 获取完整错误信息。 
            last_error = detail  # 保存最后一次错误。 
            if attempt < 3 and _is_retryable_api_exception(exc):  # 可重试错误等待后重试。 
                time.sleep(5 * attempt) 
                continue 
            return False, f"创建实例失败: {detail}", {}  # 返回失败状态与错误信息。 
    return False, f"创建实例失败: {last_error}", {}  # 理论兜底返回。 

def create_default_instance(  # 使用默认配置创建 ECS 实例。 
    region: Optional[str],  # 地域，未传则读取默认配置。 
    subnet_id: str,  # 子网 ID，必填。 
    security_group_id: str,  # 安全组 ID，必填。 
    group_index: int = 1,  # 资源命名分组，1 或 2。 
    ak: Optional[str] = None,  # AK，可选，优先级高。 
    sk: Optional[str] = None,  # SK，可选，优先级高。 
) -> Tuple[bool, str, Dict]:  # 返回调用状态与结果数据。 
    region_value = _resolve_region(region)  # 获取地域值用于映射镜像与可用区。 
    image_id = data.ECS_IMAGE_MAP.get(region_value, "")  # 按地域获取镜像 ID。 
    zone_id = data.SUBNET_ZONE_MAP.get(region_value, "")  # 按地域获取可用区 ID。 
    instance_name = data.ECS_NAME_GROUP_2 if group_index == 2 else data.ECS_NAME_GROUP_1  # 根据分组选择实例名称。 
    return run_instances(  # 调用统一创建实例方法。 
        region=region_value,  # 传入地域或使用默认值。 
        subnet_id=subnet_id,  # 传入子网 ID。 
        security_group_id=security_group_id,  # 传入安全组 ID。 
        instance_name=instance_name,  # 使用分组对应实例名称。 
        image_id=image_id,  # 使用地域对应镜像。 
        instance_type_id=data.ECS_INSTANCE_TYPE,  # 使用默认实例规格。 
        password=data.ECS_PASSWORD,  # 使用默认登录密码。 
        zone_id=zone_id,  # 使用默认可用区。 
        primary_ip=data.ECS_PRIMARY_IP,  # 设置主网卡 IP。 
        primary_extra_ips=data.ECS_PRIMARY_EXTRA_IPS,  # 设置主网卡附加 IP。 
        secondary_ip=data.ECS_SECONDARY_IP,  # 设置副网卡 IP。 
        secondary_extra_ips=data.ECS_SECONDARY_EXTRA_IPS,  # 设置副网卡附加 IP。 
        system_disk_size=data.ECS_SYSTEM_DISK_SIZE,  # 设置系统盘大小。 
        system_disk_type=data.ECS_SYSTEM_DISK_TYPE,  # 设置系统盘类型。 
        charge_type=data.ECS_CHARGE_TYPE,  # 设置计费方式。 
        count=data.ECS_INSTANCE_COUNT,  # 设置创建数量。 
        project_name=data.VPC_PROJECT_NAME,  # 使用默认项目名称。 
        ak=ak,  # 传入 AK。 
        sk=sk,  # 传入 SK。 
    )  # 返回创建实例结果。 

def describe_instance_network_interfaces(  # 查询实例网卡信息。 
    region: Optional[str],  # 地域，未传则读取默认配置。 
    instance_id: str,  # 实例 ID，必填。 
    ak: Optional[str] = None,  # AK，可选，优先级高。 
    sk: Optional[str] = None,  # SK，可选，优先级高。 
) -> Tuple[bool, str, List[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 instance_id:  # 若实例 ID 为空则返回失败。 
        return False, "InstanceId 为空，无法查询网卡", []  # 返回缺失提示。 
    configuration = _build_configuration(ak_value, sk_value, region_value)  # 构建 SDK 配置对象。 
    volcenginesdkcore.Configuration.set_default(configuration)  # 设置 SDK 默认配置供后续调用。 
    api_instance = volcenginesdkecs.ECSApi()  # 创建 ECS API 实例。 
    request = volcenginesdkecs.DescribeInstancesRequest(  # 构建查询实例请求。 
        instance_ids=[instance_id],  # 按实例 ID 精确查询。 
    )  # 查询请求构建结束。 
    try:  # 捕获 SDK 调用异常。 
        response = api_instance.describe_instances(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  # 兼容不同响应结构。 
    instances = result.get("Instances") or result.get("instances") or []  # 取出实例列表。 
    if not instances:  # 若实例列表为空则返回失败。 
        return False, "未查询到实例信息", []  # 返回缺失提示。 
    instance_info = instances[0]  # 取第一条实例信息。 
    network_interfaces = (  # 提取网卡信息列表。 
        instance_info.get("NetworkInterfaces") 
        or instance_info.get("network_interfaces") 
        or [] 
    )  # 网卡信息提取结束。 
    return True, "查询实例网卡成功", network_interfaces  # 返回查询结果。 

def wait_for_instance_network_interfaces(  # 等待实例网卡信息就绪。 
    region: Optional[str],  # 地域，未传则读取默认配置。 
    instance_id: str,  # 实例 ID，必填。 
    expected_count: int = 2,  # 期望的网卡数量。 
    timeout: int = 90,  # 最大等待时长（秒）。 
    interval: int = 3,  # 轮询间隔秒数。 
    ak: Optional[str] = None,  # AK，可选，优先级高。 
    sk: Optional[str] = None,  # SK，可选，优先级高。 
    progress_callback: Optional[Callable[[int, int, int, int], None]] = None,  # 每次查询后的简短进度回调。 
) -> Tuple[bool, str, List[Dict]]:  # 返回调用状态、提示与网卡列表。 
    start_time = time.time()  # 记录开始时间用于超时判断。 
    last_error = ""  # 记录最后一次错误信息便于输出。 
    attempt = 0  # 记录当前查询次数。 
    max_attempts = max(1, (timeout + interval - 1) // interval)  # 计算最大查询次数。 
    while time.time() - start_time < timeout:  # 在超时前持续轮询。 
        attempt += 1  # 每次云接口查询递增一次。 
        ok, message, nics = describe_instance_network_interfaces(  # 调用查询网卡方法。 
            region=region,  # 传入地域或使用默认值。 
            instance_id=instance_id,  # 传入实例 ID。 
            ak=ak,  # 传入 AK。 
            sk=sk,  # 传入 SK。 
        )  # 查询调用结束。 
        if progress_callback:  # 将本次查询结果输出给调用方。 
            progress_callback(attempt, max_attempts, len(nics) if ok else 0, expected_count) 
        if ok:  # 查询成功时判断网卡数量是否满足预期。 
            if expected_count <= 0:  # 若不要求数量则直接返回。 
                return True, "网卡信息已就绪", nics  # 返回成功结果。 
            if len(nics) >= expected_count:  # 满足预期数量时返回成功。 
                return True, "网卡信息已就绪", nics  # 返回成功结果。 
        else:  # 查询失败时记录错误信息。 
            last_error = message  # 保存错误信息便于超时输出。 
        time.sleep(interval)  # 等待后继续轮询。 
    return False, last_error or "等待实例网卡信息超时", []  # 超时后返回失败。 

def describe_instance_status(  # 查询实例状态。 
    region: Optional[str],  # 地域，未传则读取默认配置。 
    instance_id: str,  # 实例 ID，必填。 
    ak: Optional[str] = None,  # AK，可选，优先级高。 
    sk: Optional[str] = None,  # SK，可选，优先级高。 
) -> Tuple[bool, str, str]:  # 返回调用状态、提示与实例状态。 
    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 instance_id:  # 若实例 ID 为空则返回失败。 
        return False, "InstanceId 为空，无法查询实例状态", ""  # 返回缺失提示。 
    configuration = _build_configuration(ak_value, sk_value, region_value)  # 构建 SDK 配置对象。 
    volcenginesdkcore.Configuration.set_default(configuration)  # 设置 SDK 默认配置供后续调用。 
    api_instance = volcenginesdkecs.ECSApi()  # 创建 ECS API 实例。 
    request = volcenginesdkecs.DescribeInstancesRequest(  # 构建查询实例请求。 
        instance_ids=[instance_id],  # 按实例 ID 精确查询。 
    )  # 查询请求构建结束。 
    try:  # 捕获 SDK 调用异常。 
        response = api_instance.describe_instances(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  # 兼容不同响应结构。 
    instances = result.get("Instances") or result.get("instances") or []  # 取出实例列表。 
    if not instances:  # 若实例列表为空则返回失败。 
        return False, "未查询到实例信息", ""  # 返回缺失提示。 
    instance_info = instances[0]  # 取第一条实例信息。 
    status = instance_info.get("Status") or instance_info.get("status") or ""  # 提取实例状态。 
    return True, "查询实例状态成功", status  # 返回查询结果。 

def wait_for_instance_running(  # 等待实例进入运行状态。 
    region: Optional[str],  # 地域，未传则读取默认配置。 
    instance_id: str,  # 实例 ID，必填。 
    timeout: int = 120,  # 最大等待时长（秒）。 
    interval: int = 5,  # 轮询间隔秒数。 
    ak: Optional[str] = None,  # AK，可选，优先级高。 
    sk: Optional[str] = None,  # SK，可选，优先级高。 
    progress_callback: Optional[Callable[[int, int, str], None]] = None,  # 每次查询后的简短进度回调。 
) -> Tuple[bool, str, str]:  # 返回调用状态、提示与实例状态。 
    start_time = time.time()  # 记录开始时间用于超时判断。 
    last_status = ""  # 记录最近状态便于输出。 
    last_error = ""  # 记录最后一次错误信息便于输出。 
    attempt = 0  # 记录当前查询次数。 
    max_attempts = max(1, (timeout + interval - 1) // interval)  # 计算最大查询次数。 
    while time.time() - start_time < timeout:  # 在超时前持续轮询。 
        attempt += 1  # 每次云接口查询递增一次。 
        ok, message, status = describe_instance_status(  # 调用查询实例状态方法。 
            region=region,  # 传入地域或使用默认值。 
            instance_id=instance_id,  # 传入实例 ID。 
            ak=ak,  # 传入 AK。 
            sk=sk,  # 传入 SK。 
        )  # 查询调用结束。 
        if progress_callback:  # 将本次查询结果输出给调用方。 
            progress_callback(attempt, max_attempts, status if ok else "") 
        if ok:  # 查询成功时判断状态是否就绪。 
            last_status = status  # 保存最新状态。 
            if status.upper() == "RUNNING":  # 达到运行状态则返回成功。 
                return True, "实例已运行", status  # 返回成功结果。 
        else:  # 查询失败时记录错误信息。 
            last_error = message  # 保存错误信息便于超时输出。 
        time.sleep(interval)  # 等待后继续轮询。 
    if last_error:  # 若有错误信息则返回错误。 
        return False, last_error, last_status  # 返回失败结果。 
    return False, f"等待实例运行超时 (最后状态: {last_status or '未知'})", last_status  # 超时后返回失败。 
