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

def create_default_security_group(  # 按默认配置创建安全组。 
    region: Optional[str],  # 地域，未传则读取默认配置。 
    vpc_id: str,  # VPC ID。 
    group_index: int = 1,  # 资源命名分组，1 或 2。 
) -> Tuple[bool, str, Dict]:  # 返回创建结果。 
    sg_name = data.SECURITY_GROUP_NAME_GROUP_2 if group_index == 2 else data.SECURITY_GROUP_NAME_GROUP_1  # 根据分组选择名称。 
    return create_security_group(  # 调用通用创建方法。 
        region=region,  # 传入地域或使用默认值。 
        vpc_id=vpc_id,  # 传入 VPC ID。 
        security_group_name=sg_name,  # 使用分组对应的安全组名称。 
        description=data.SECURITY_GROUP_DESCRIPTION,  # 使用默认描述。 
        project_name=data.SECURITY_GROUP_PROJECT_NAME,  # 使用默认项目名称。 
    )  # 返回创建结果。 

def find_security_group_by_name(  # 按名称查询安全组。 
    region: Optional[str],  # 地域，未传则读取默认配置。 
    security_group_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(security_group_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, "SecurityGroupName 为空，无法查询安全组", {}  # 返回缺失提示。 
    configuration = _build_configuration(ak_value, sk_value, region_value)  # 构建 SDK 配置对象。 
    volcenginesdkcore.Configuration.set_default(configuration)  # 设置 SDK 默认配置供后续调用。 
    api_instance = volcenginesdkvpc.VPCApi()  # 创建 VPC API 实例。 
    try:  # 尝试使用名称过滤。 
        params = {"security_group_names": [name_value]}  # 构建查询参数。 
        if vpc_value:  # 仅在 VPC ID 存在时加入过滤。 
            params["vpc_id"] = vpc_value  # 加入 VPC ID 过滤。 
        request = volcenginesdkvpc.DescribeSecurityGroupsRequest(**params)  # 构建请求对象。 
    except TypeError:  # 捕获参数不匹配时降级为全量查询。 
        request = volcenginesdkvpc.DescribeSecurityGroupsRequest()  # 无过滤参数的请求对象。 
    try:  # 捕获 SDK 调用异常。 
        response = api_instance.describe_security_groups(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  # 兼容不同响应结构。 
    sg_list = result.get("SecurityGroups") or result.get("security_groups") or result.get("SecurityGroupSet") or []  # 提取安全组列表。 
    for item in sg_list:  # 遍历安全组列表查找目标名称。 
        item_name = item.get("SecurityGroupName") or item.get("security_group_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, "未找到目标安全组", {}  # 未找到目标安全组时返回失败。 

def describe_security_group_status(  # 查询安全组状态的统一入口。 
    region: Optional[str],  # 地域，未传则读取默认配置。 
    security_group_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 为空，无法查询安全组状态", ""  # 返回缺失提示。 
    if not region_value:  # 若 region 为空则返回失败。 
        return False, "地域为空，无法查询安全组状态", ""  # 返回缺失提示。 
    if not security_group_id:  # 若安全组 ID 为空则返回失败。 
        return False, "SecurityGroupId 为空，无法查询安全组状态", ""  # 返回缺失提示。 
    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:  # 尝试使用 security_group_ids 过滤。 
        request = volcenginesdkvpc.DescribeSecurityGroupsRequest(security_group_ids=[security_group_id])  # 构建带过滤条件的请求。 
    except TypeError:  # 捕获参数名不匹配情况。 
        request = volcenginesdkvpc.DescribeSecurityGroupsRequest()  # 降级为无过滤参数。 
    try:  # 捕获 SDK 调用异常。 
        response = api_instance.describe_security_groups(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  # 兼容不同响应结构。 
    sg_list = result.get("SecurityGroups") or result.get("security_groups") or result.get("SecurityGroupSet") or []  # 提取安全组列表。 
    for item in sg_list:  # 遍历安全组列表查找目标安全组。 
        item_id = item.get("SecurityGroupId") or item.get("security_group_id")  # 提取安全组 ID。 
        if item_id != security_group_id:  # 若非目标安全组则跳过。 
            continue  # 跳过当前条目。 
        status = item.get("Status") or item.get("status") or ""  # 提取安全组状态。 
        return True, "查询安全组状态成功", str(status)  # 返回状态字符串。 
    return False, "未找到目标安全组", ""  # 未找到目标安全组时返回失败。 

def wait_for_security_group_available(  # 等待安全组状态就绪。 
    region: Optional[str],  # 地域，未传则读取默认配置。 
    security_group_id: str,  # 目标安全组 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_security_group_status(region, security_group_id, ak, sk)  # 查询安全组当前状态。 
        if ok and status:  # 若查询成功且有状态值。 
            normalized = status.strip().lower()  # 统一状态字符串大小写。 
            if normalized in {"available", "active", "ok", "running"}:  # 判断是否已就绪。 
                return True, "安全组状态就绪"  # 返回就绪结果。 
        time.sleep(interval_seconds)  # 未就绪则等待后继续轮询。 
    return False, f"等待安全组就绪超时({timeout_seconds}s)"  # 超时后返回失败。 

def authorize_security_group_rule(  # 授权安全组规则的通用入口。 
    region: Optional[str],  # 地域，未传则读取默认配置。 
    security_group_id: str,  # 安全组 ID。 
    direction: str,  # 规则方向，支持 ingress/egress。 
    protocol: str,  # 协议名称，例如 tcp/udp/gre。 
    cidr_ip: str,  # 放行的 CIDR 网段。 
    port_start: Optional[int] = None,  # 起始端口，可选。 
    port_end: Optional[int] = None,  # 结束端口，可选。 
    description: Optional[str] = None,  # 规则描述，可选。 
    policy: Optional[str] = None,  # 规则策略，可选。 
    priority: Optional[int] = 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 配置", {}  # 返回缺失提示。 
    if not security_group_id:  # 若安全组 ID 为空则返回失败。 
        return False, "SecurityGroupId 为空，无法授权规则", {}  # 返回缺失提示。 
    direction_value = _normalize(direction).lower()  # 规范化方向参数。 
    if direction_value not in {"ingress", "egress"}:  # 校验方向参数是否合法。 
        return False, "规则方向必须为 ingress 或 egress", {}  # 返回参数错误提示。 
    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 = {  # 构建基础参数，避免传递空字段导致校验失败。 
        "security_group_id": security_group_id,  # 写入安全组 ID。 
        "protocol": _normalize(protocol),  # 写入协议名称。 
        "cidr_ip": _normalize(cidr_ip),  # 写入放行网段。 
        "client_token": token_value,  # 写入幂等 Token。 
    }  # 基础参数构建结束。 
    if port_start is not None:  # 仅在端口不为空时传入。 
        params["port_start"] = port_start  # 写入起始端口。 
    if port_end is not None:  # 仅在端口不为空时传入。 
        params["port_end"] = port_end  # 写入结束端口。 
    desc_value = _normalize(description)  # 清理规则描述空格。 
    if desc_value:  # 仅在描述非空时传入。 
        params["description"] = desc_value  # 写入规则描述。 
    policy_value = _normalize(policy)  # 清理策略字段空格。 
    if policy_value:  # 仅在策略非空时传入。 
        params["policy"] = policy_value  # 写入策略字段。 
    params["priority"] = 1 if priority is None else priority  # 图片要求优先级为 1；未显式指定时按 1 写入。
    try:  # 捕获 SDK 调用异常。 
        if direction_value == "ingress":  # 处理入方向规则。 
            request = volcenginesdkvpc.AuthorizeSecurityGroupIngressRequest(**params)  # 构建入方向请求。 
            response = api_instance.authorize_security_group_ingress(request)  # 调用入方向授权接口。 
        else:  # 处理出方向规则。 
            request = volcenginesdkvpc.AuthorizeSecurityGroupEgressRequest(**params)  # 构建出方向请求。 
            response = api_instance.authorize_security_group_egress(request)  # 调用出方向授权接口。 
    except ApiException as exc:  # 捕获火山 SDK 抛出的异常。 
        error_text = str(exc)  # 转换异常文本用于判断规则是否已存在。 
        error_lower = error_text.lower()  # 小写文本用于兼容不同错误格式。 
        if (
            "duplicate" in error_lower
            or "alreadyexist" in error_lower
            or "already exists" in error_lower
            or "invalidsecurityrule.conflict" in error_lower
            or "security rule conflicts" in error_lower
            or "conflicts with that of another security rule" in error_lower
            or "已存在" in error_text
        ):  # 已有/冲突规则视为成功，继续后续网卡和 EIP 绑定。
            return True, "安全组规则已存在或冲突，已跳过重复授权", {}
        return False, f"安全组规则授权失败: {exc}", {}  # 返回失败状态与错误信息。 
    data_dict = _to_dict(response)  # 将响应对象转换为字典。 
    return True, "安全组规则授权成功", data_dict  # 返回成功状态与结果。 

def _permission_field(permission: Dict, *keys: str):
    for key in keys:
        if key in permission and permission.get(key) is not None:
            return permission.get(key)
    return None

def _permission_int(value, default: int = -1) -> int:
    try:
        return int(value)
    except Exception:
        return default

def _permission_key(permission: Dict) -> Tuple[str, str, int, int, str]:
    return (
        str(_permission_field(permission, "Direction", "direction") or "").lower(),
        str(_permission_field(permission, "Protocol", "protocol") or "").lower(),
        _permission_int(_permission_field(permission, "PortStart", "port_start")),
        _permission_int(_permission_field(permission, "PortEnd", "port_end")),
        str(_permission_field(permission, "CidrIp", "cidr_ip") or ""),
    )

def describe_security_group_ingress_rules(
    region: Optional[str],
    security_group_id: str,
    ak: Optional[str] = None,
    sk: Optional[str] = None,
) -> Tuple[bool, str, List[Dict]]:
    ak_value, sk_value = _resolve_credentials(ak, sk)
    region_value = _resolve_region(region)
    if not ak_value or not sk_value:
        return False, "AK/SK 为空，无法查询安全组规则", []
    if not region_value:
        return False, "地域为空，无法查询安全组规则", []
    if not security_group_id:
        return False, "SecurityGroupId 为空，无法查询安全组规则", []
    configuration = _build_configuration(ak_value, sk_value, region_value)
    volcenginesdkcore.Configuration.set_default(configuration)
    api_instance = volcenginesdkvpc.VPCApi()
    request = volcenginesdkvpc.DescribeSecurityGroupAttributesRequest(
        security_group_id=security_group_id,
        direction="ingress",
    )
    try:
        response = api_instance.describe_security_group_attributes(request)
    except ApiException as exc:
        return False, f"查询安全组规则失败: {exc}", []
    data_dict = _to_dict(response)
    result = data_dict.get("Result") or data_dict.get("result") or data_dict
    permissions = result.get("Permissions") or result.get("permissions") or []
    return True, "查询安全组规则成功", list(permissions)

def revoke_security_group_ingress_rule(
    region: Optional[str],
    security_group_id: str,
    permission: Dict,
    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)
    if not ak_value or not sk_value:
        return False, "AK/SK 为空，无法撤销安全组规则", {}
    if not region_value:
        return False, "地域为空，无法撤销安全组规则", {}
    protocol = str(_permission_field(permission, "Protocol", "protocol") or "").lower()
    cidr_ip = str(_permission_field(permission, "CidrIp", "cidr_ip") or "")
    if not security_group_id or not protocol or not cidr_ip:
        return False, "安全组规则信息不完整，无法撤销", {}
    params = {
        "security_group_id": security_group_id,
        "protocol": protocol,
        "cidr_ip": cidr_ip,
        "port_start": _permission_int(_permission_field(permission, "PortStart", "port_start")),
        "port_end": _permission_int(_permission_field(permission, "PortEnd", "port_end")),
    }
    policy = _permission_field(permission, "Policy", "policy")
    priority = _permission_field(permission, "Priority", "priority")
    description = _permission_field(permission, "Description", "description")
    if policy:
        params["policy"] = str(policy)
    if priority is not None:
        params["priority"] = _permission_int(priority, 1)
    if description:
        params["description"] = str(description)
    configuration = _build_configuration(ak_value, sk_value, region_value)
    volcenginesdkcore.Configuration.set_default(configuration)
    api_instance = volcenginesdkvpc.VPCApi()
    try:
        request = volcenginesdkvpc.RevokeSecurityGroupIngressRequest(**params)
        response = api_instance.revoke_security_group_ingress(request)
    except ApiException as exc:
        error_text = str(exc).lower()
        if "notfound" in error_text or "not found" in error_text or "invalidsecurityrule.notfound" in error_text:
            return True, "安全组规则已不存在", {}
        return False, f"撤销安全组规则失败: {exc}", {}
    return True, "撤销安全组规则成功", _to_dict(response)

def revoke_unwanted_ingress_rules(
    region: Optional[str],
    security_group_id: str,
    desired_keys: set[Tuple[str, str, int, int, str]],
) -> None:
    ok, _message, permissions = describe_security_group_ingress_rules(region, security_group_id)
    if not ok:
        return
    for permission in permissions:
        key = _permission_key(permission)
        if key[0] != "ingress" or key in desired_keys:
            continue
        revoke_security_group_ingress_rule(region, security_group_id, permission)

def apply_default_security_group_rules(  # 批量应用默认安全组规则。 
    region: Optional[str],  # 地域，未传则读取默认配置。 
    security_group_id: str,  # 安全组 ID。 
) -> Tuple[bool, str, Dict]:  # 返回应用状态与结果汇总。 
    ok, wait_message = wait_for_security_group_available(region, security_group_id)  # 等待安全组状态就绪再授权规则。 
    if not ok:  # 判断等待是否失败。 
        return False, wait_message, {}  # 返回等待失败原因。 
    results: List[Dict] = []  # 存放每条规则的返回结果。 
    cidr_value = data.SECURITY_GROUP_RULE_CIDR  # 读取默认放行网段。 
    policy_value = data.SECURITY_GROUP_RULE_POLICY  # 读取默认策略。 
    def normalize_port_range(port_value):
        if isinstance(port_value, (list, tuple)) and len(port_value) >= 2:
            start = int(port_value[0])
            end = int(port_value[1])
        else:
            start = int(port_value)
            end = int(port_value)
        return start, end
    desired_ingress_keys: set[Tuple[str, str, int, int, str]] = set()
    for port in data.SECURITY_GROUP_TCP_PORTS:
        port_start, port_end = normalize_port_range(port)
        desired_ingress_keys.add(("ingress", "tcp", port_start, port_end, cidr_value))
    for port in data.SECURITY_GROUP_UDP_PORTS:
        port_start, port_end = normalize_port_range(port)
        desired_ingress_keys.add(("ingress", "udp", port_start, port_end, cidr_value))
    if _normalize(data.SECURITY_GROUP_GRE_PROTOCOL):
        desired_ingress_keys.add(("ingress", _normalize(data.SECURITY_GROUP_GRE_PROTOCOL), 0, 0, cidr_value))
    icmp_protocol = _normalize(getattr(data, "SECURITY_GROUP_ICMP_PROTOCOL", ""))
    if icmp_protocol:
        desired_ingress_keys.add(("ingress", icmp_protocol, -1, -1, cidr_value))
    if getattr(data, "SECURITY_GROUP_OPEN_ALL", False):  # 火山官方全开规则：Protocol=all，端口填 -1。 
        for direction in ("ingress", "egress"):  # 入方向与出方向各创建一次。 
            ok, message, result = authorize_security_group_rule(  # 调用规则授权方法。 
                region=region,  # 传入地域或使用默认值。 
                security_group_id=security_group_id,  # 传入安全组 ID。 
                direction=direction,  # 传入规则方向。 
                protocol="all",  # 放开全部协议。 
                cidr_ip=cidr_value,  # 设置放行网段。 
                port_start=-1,  # all 协议按官方要求填 -1 表示不限制端口。 
                port_end=-1,  # all 协议按官方要求填 -1 表示不限制端口。 
                description="auto all protocols",  # 设置规则描述。 
                policy=policy_value,  # 设置规则策略。 
            )  # 调用结束。 
            if not ok and "InvalidSecurityGroup.InvalidStatus" in message:  # 若安全组未就绪则等待后重试一次。 
                wait_ok, wait_message = wait_for_security_group_available(region, security_group_id)  # 再次等待安全组就绪。 
                if not wait_ok:  # 判断等待是否失败。 
                    return False, wait_message, {}  # 返回等待失败原因。 
                ok, message, result = authorize_security_group_rule(  # 重新调用规则授权方法。 
                    region=region,  # 传入地域或使用默认值。 
                    security_group_id=security_group_id,  # 传入安全组 ID。 
                    direction=direction,  # 传入规则方向。 
                    protocol="all",  # 放开全部协议。 
                    cidr_ip=cidr_value,  # 设置放行网段。 
                    port_start=-1,  # all 协议按官方要求填 -1 表示不限制端口。 
                    port_end=-1,  # all 协议按官方要求填 -1 表示不限制端口。 
                    description="auto all protocols",  # 设置规则描述。 
                    policy=policy_value,  # 设置规则策略。 
                )  # 重新调用结束。 
            if not ok:  # 判断规则授权是否失败。 
                return False, message, {}  # 返回失败状态与错误信息。 
            results.append(result)  # 保存规则返回结果。 
        return True, "安全组规则全部授权成功", {"rules": results}  # 全开模式下不再逐端口授权。 
    revoke_unwanted_ingress_rules(region, security_group_id, desired_ingress_keys)
    for port in data.SECURITY_GROUP_TCP_PORTS:  # 遍历 TCP 端口规则。 
        port_start, port_end = normalize_port_range(port)
        desc = f"auto tcp {port_start}-{port_end}"  # 生成规则描述。 
        for direction in ("ingress",):  # 按截图仅创建入方向规则。 
            ok, message, result = authorize_security_group_rule(  # 调用规则授权方法。 
                region=region,  # 传入地域或使用默认值。 
                security_group_id=security_group_id,  # 传入安全组 ID。 
                direction=direction,  # 传入规则方向。 
                protocol="tcp",  # 设置协议为 TCP。 
                cidr_ip=cidr_value,  # 设置放行网段。 
                port_start=port_start,  # 设置起始端口。 
                port_end=port_end,  # 设置结束端口。 
                description=desc,  # 设置规则描述。 
                policy=policy_value,  # 设置规则策略。 
            )  # 调用结束。 
            if not ok and "InvalidSecurityGroup.InvalidStatus" in message:  # 若安全组未就绪则等待后重试一次。 
                wait_ok, wait_message = wait_for_security_group_available(region, security_group_id)  # 再次等待安全组就绪。 
                if not wait_ok:  # 判断等待是否失败。 
                    return False, wait_message, {}  # 返回等待失败原因。 
                ok, message, result = authorize_security_group_rule(  # 重新调用规则授权方法。 
                    region=region,  # 传入地域或使用默认值。 
                    security_group_id=security_group_id,  # 传入安全组 ID。 
                    direction=direction,  # 传入规则方向。 
                    protocol="tcp",  # 设置协议为 TCP。 
                    cidr_ip=cidr_value,  # 设置放行网段。 
                    port_start=port_start,  # 设置起始端口。 
                    port_end=port_end,  # 设置结束端口。 
                    description=desc,  # 设置规则描述。 
                    policy=policy_value,  # 设置规则策略。 
                )  # 重新调用结束。 
            if not ok:  # 判断规则授权是否失败。 
                return False, message, {}  # 返回失败状态与错误信息。 
            results.append(result)  # 保存规则返回结果。 
    for port in data.SECURITY_GROUP_UDP_PORTS:  # 遍历 UDP 端口规则。 
        port_start, port_end = normalize_port_range(port)
        desc = f"auto udp {port_start}-{port_end}"  # 生成规则描述。 
        for direction in ("ingress",):  # 按截图仅创建入方向规则。 
            ok, message, result = authorize_security_group_rule(  # 调用规则授权方法。 
                region=region,  # 传入地域或使用默认值。 
                security_group_id=security_group_id,  # 传入安全组 ID。 
                direction=direction,  # 传入规则方向。 
                protocol="udp",  # 设置协议为 UDP。 
                cidr_ip=cidr_value,  # 设置放行网段。 
                port_start=port_start,  # 设置起始端口。 
                port_end=port_end,  # 设置结束端口。 
                description=desc,  # 设置规则描述。 
                policy=policy_value,  # 设置规则策略。 
            )  # 调用结束。 
            if not ok and "InvalidSecurityGroup.InvalidStatus" in message:  # 若安全组未就绪则等待后重试一次。 
                wait_ok, wait_message = wait_for_security_group_available(region, security_group_id)  # 再次等待安全组就绪。 
                if not wait_ok:  # 判断等待是否失败。 
                    return False, wait_message, {}  # 返回等待失败原因。 
                ok, message, result = authorize_security_group_rule(  # 重新调用规则授权方法。 
                    region=region,  # 传入地域或使用默认值。 
                    security_group_id=security_group_id,  # 传入安全组 ID。 
                    direction=direction,  # 传入规则方向。 
                    protocol="udp",  # 设置协议为 UDP。 
                    cidr_ip=cidr_value,  # 设置放行网段。 
                    port_start=port_start,  # 设置起始端口。 
                    port_end=port_end,  # 设置结束端口。 
                    description=desc,  # 设置规则描述。 
                    policy=policy_value,  # 设置规则策略。 
                )  # 重新调用结束。 
            if not ok:  # 判断规则授权是否失败。 
                return False, message, {}  # 返回失败状态与错误信息。 
            results.append(result)  # 保存规则返回结果。 
    gre_protocol = _normalize(data.SECURITY_GROUP_GRE_PROTOCOL)  # 读取 GRE 协议标识。 
    if gre_protocol:  # 仅当 GRE 协议标识非空时创建规则。 
        desc = f"auto {gre_protocol} 47"  # 生成 GRE 规则描述。 
        for direction in ("ingress",):  # 按截图仅创建入方向规则。 
            ok, message, result = authorize_security_group_rule(  # 调用规则授权方法。 
                region=region,  # 传入地域或使用默认值。 
                security_group_id=security_group_id,  # 传入安全组 ID。 
                direction=direction,  # 传入规则方向。 
                protocol=gre_protocol,  # 设置协议为 GRE。 
                cidr_ip=cidr_value,  # 设置放行网段。 
                port_start=0,  # GRE 协议不使用端口，填 0 以满足 SDK 必填校验。 
                port_end=0,  # GRE 协议不使用端口，填 0 以满足 SDK 必填校验。 
                description=desc,  # 设置规则描述。 
                policy=policy_value,  # 设置规则策略。 
            )  # 调用结束。 
            if not ok and "InvalidSecurityGroup.InvalidStatus" in message:  # 若安全组未就绪则等待后重试一次。 
                wait_ok, wait_message = wait_for_security_group_available(region, security_group_id)  # 再次等待安全组就绪。 
                if not wait_ok:  # 判断等待是否失败。 
                    return False, wait_message, {}  # 返回等待失败原因。 
                ok, message, result = authorize_security_group_rule(  # 重新调用规则授权方法。 
                    region=region,  # 传入地域或使用默认值。 
                    security_group_id=security_group_id,  # 传入安全组 ID。 
                    direction=direction,  # 传入规则方向。 
                    protocol=gre_protocol,  # 设置协议为 GRE。 
                    cidr_ip=cidr_value,  # 设置放行网段。 
                    port_start=0,  # GRE 协议不使用端口，填 0 以满足 SDK 必填校验。 
                    port_end=0,  # GRE 协议不使用端口，填 0 以满足 SDK 必填校验。 
                    description=desc,  # 设置规则描述。 
                    policy=policy_value,  # 设置规则策略。 
                )  # 重新调用结束。 
            if not ok:  # 判断规则授权是否失败。 
                return False, message, {}  # 返回失败状态与错误信息。 
            results.append(result)  # 保存规则返回结果。 
    if icmp_protocol:  # 仅当 ICMP 协议标识非空时创建规则。 
        desc = f"auto {icmp_protocol} all"  # 生成 ICMP 规则描述。 
        for direction in ("ingress",):  # 按截图仅创建入方向规则。 
            ok, message, result = authorize_security_group_rule(  # 调用规则授权方法。 
                region=region,  # 传入地域或使用默认值。 
                security_group_id=security_group_id,  # 传入安全组 ID。 
                direction=direction,  # 传入规则方向。 
                protocol=icmp_protocol,  # 设置协议为 ICMP。 
                cidr_ip=cidr_value,  # 设置放行网段。 
                port_start=-1,  # ICMP 不使用端口，按 ALL 语义填 -1。 
                port_end=-1,  # ICMP 不使用端口，按 ALL 语义填 -1。 
                description=desc,  # 设置规则描述。 
                policy=policy_value,  # 设置规则策略。 
            )  # 调用结束。 
            if not ok and "InvalidSecurityGroup.InvalidStatus" in message:  # 若安全组未就绪则等待后重试一次。 
                wait_ok, wait_message = wait_for_security_group_available(region, security_group_id)  # 再次等待安全组就绪。 
                if not wait_ok:  # 判断等待是否失败。 
                    return False, wait_message, {}  # 返回等待失败原因。 
                ok, message, result = authorize_security_group_rule(  # 重新调用规则授权方法。 
                    region=region,  # 传入地域或使用默认值。 
                    security_group_id=security_group_id,  # 传入安全组 ID。 
                    direction=direction,  # 传入规则方向。 
                    protocol=icmp_protocol,  # 设置协议为 ICMP。 
                    cidr_ip=cidr_value,  # 设置放行网段。 
                    port_start=-1,  # ICMP 不使用端口，按 ALL 语义填 -1。 
                    port_end=-1,  # ICMP 不使用端口，按 ALL 语义填 -1。 
                    description=desc,  # 设置规则描述。 
                    policy=policy_value,  # 设置规则策略。 
                )  # 重新调用结束。 
            if not ok:  # 判断规则授权是否失败。 
                return False, message, {}  # 返回失败状态与错误信息。 
            results.append(result)  # 保存规则返回结果。 
    return True, "安全组规则全部授权成功", {"rules": results}  # 返回成功状态与结果汇总。 
