from config import PROJECT_ID, DEFAULT_REGION_ID, get_runtime_ak_sk  # 导入鉴权参数与默认区域用于流程调用。 
from data import REGION_SPECS, REGION_ID_MAP, REGIONS_5IP, DELTA_MODE_SPEC_OVERRIDES, TWENTY_MODE_SPEC_OVERRIDES  # 导入地区规格与 regionId 映射。
from data import LOG_ENABLED, OUTPUT_SUMMARY  # 导入日志与结果输出开关。 
from data import RUN_ALL_REGIONS, ALL_REGION_KEYS, CONTINUE_ON_ERROR  # 导入批量运行控制参数。 
from data import REGION_DISPLAY_NAMES, PASSWORD  # 导入地区中文名与默认密码。 
from data import CONSOLE_PRELOAD_ENABLED, CONSOLE_ECS_URLS_BY_REGION_ID  # 导入购买前控制台页面预热配置。
from data import CONSOLE_PRELOAD_TIMEOUT_SECONDS, CONSOLE_PRELOAD_RETRY_ATTEMPTS, CONSOLE_PRELOAD_RETRY_DELAY_SECONDS  # 导入控制台预热重试参数。
from vpc_service import create_vpc  # 导入创建 VPC 的实现函数。 
from subnet_service import create_subnet  # 导入创建子网的实现函数。 
from security_group_service import create_security_group  # 导入创建安全组的实现函数。 
from ecs_service import purchase_server  # 导入购买服务器的实现函数。 
from nic_service import create_aux_nic, get_aux_nic_details  # 导入申请与查询辅助网卡的实现函数。 
from eip_service import allocate_eip, bind_eip, get_server_ports, get_public_ips_by_port  # 导入公网 IP 申请与绑定函数。
from vip_service import create_virtual_ips  # 导入 20 规格虚拟 IP 创建与绑定函数。
from iam_service import get_project_id  # 导入项目 ID 查询函数用于购买前预检。 
import os  # 导入系统模块用于读取 API 子进程传入的地区。
import threading  # 导入线程模块用于线程局部日志前缀管理。
import concurrent.futures  # 限制地区并发，避免华为云 API 瞬时连接超时被放大。
import time  # 导入时间模块用于控制台页面预热失败后的短等待。
import urllib.error  # 导入 URL 异常模块用于识别控制台页面访问失败。
import urllib.request  # 导入标准库 HTTP 客户端，避免引入浏览器/requests 依赖。
_LOG_LOCAL = threading.local()  # 创建线程局部存储用于记录日志前缀。 
def _set_log_prefix(prefix):  # 设置当前线程日志前缀的函数。 
    _LOG_LOCAL.prefix = prefix  # 将日志前缀写入线程局部存储。 
def _get_log_prefix():  # 获取当前线程日志前缀的函数。 
    return getattr(_LOG_LOCAL, "prefix", "")  # 读取线程局部前缀，默认空字符串。 
def _resolve_region_key(region_input):  # 将输入地区转换为规格表的逻辑名。 
    region_key = str(region_input or "").strip()  # 默认先按输入作为逻辑名处理。 
    if region_key not in REGION_SPECS:  # 若输入不是逻辑名则尝试反向映射。 
        for key, value in REGION_ID_MAP.items():  # 遍历映射表查找 regionId 对应逻辑名。 
            if value == region_key:  # 若匹配到 regionId 则记录逻辑名。 
                region_key = key  # 将逻辑名赋值用于规格选择。 
                break  # 命中后退出循环减少遍历开销。 
    if region_key not in REGION_SPECS:  # 若仍未识别，再兼容前端/日志传入的中文地区名。 
        for key, label in REGION_DISPLAY_NAMES.items():  # 遍历中文地区名映射。 
            if label == region_key:  # 中文名称命中时转为内部逻辑名。 
                region_key = key  # 使用逻辑名进入后续 regionId、规格、项目 ID 解析。 
                break  # 命中后退出循环。 
    return region_key  # 返回逻辑地区名。 
def _resolve_region_id(region_key):  # 将逻辑地区名转换为真实 regionId。 
    region_id = REGION_ID_MAP.get(region_key, region_key)  # 若存在映射则替换，否则直接使用输入值。 
    return region_id  # 返回最终 regionId。 
def _resolve_purchase_mode():  # 读取本次购买模式。 
    return (os.getenv("HUAWEI_PURCHASE_MODE") or "").strip().lower()  # 返回标准化模式名。 


def _is_delta_purchase_mode() -> bool:
    return _resolve_purchase_mode() in {"delta", "x1.2u.2g", "x1.2u.29", "fixed", "x1"}


def _is_twenty_purchase_mode() -> bool:
    return _resolve_purchase_mode() in {"20", "wawacloud_20", "twenty", "x1.20"}


def _resolve_region_spec(region_key):  # 根据地区和购买模式解析最终规格。 
    spec = dict(REGION_SPECS[region_key])  # 复制地区规格，避免运行时修改全局配置。
    if _is_twenty_purchase_mode():  # 20 规格覆盖全部地区的网卡、虚拟 IP 和规格候选。
        spec.update(TWENTY_MODE_SPEC_OVERRIDES)  # 应用 20 规格拓扑。
    if _is_delta_purchase_mode():  # x1.2u.2g 模式只覆盖规格和系统盘。
        spec.update(DELTA_MODE_SPEC_OVERRIDES)  # 应用三角洲规格覆盖。
    if (
        region_key in REGIONS_5IP
        and _resolve_purchase_mode() in {"x1.1u.1g", "delta", "x1.2u.2g", "x1.2u.29", "fixed", "x1"}
        and (os.getenv("HUAWEI_X1_IP_COUNT") or "").strip() == "10"
    ):
        spec.update(
            {
                "secondary_nic_ip": "192.168.0.11",
                "extra_nic_count": 1,
                "aux_nic_count": 8,
                "aux_nic_ip_start": 12,
                "aux_nic_ip_end": 19,
            }
        )
    if _resolve_purchase_mode() in {"x1.1u.1g", "x1.20"}:
        spec["flavor"] = "x1.1u.1g"
        spec["flavor_candidates"] = ["x1.1u.1g"]
    return spec  # 返回最终规格配置。 
def _log(message):  # 统一日志输出函数。 
    if LOG_ENABLED:  # 仅在日志开关开启时输出。 
        prefix = _get_log_prefix()  # 获取线程级日志前缀。 
        if prefix:  # 若存在前缀则拼接输出。 
            print(f"[{prefix}] {message}", flush=True)  # 输出带前缀的日志内容用于区分地区，并立即回传界面。 
        else:  # 若无前缀则按原样输出。 
            print(message, flush=True)  # 输出日志内容用于排查流程问题，并避免购买预检时界面误判卡死。 
def _region_label(region_input):  # 生成地区中文名与 regionId 组合标签。 
    region_key = _resolve_region_key(region_input)  # 解析逻辑地区名。 
    region_id = _resolve_region_id(region_key)  # 解析真实 regionId。 
    region_name = REGION_DISPLAY_NAMES.get(region_key, region_key)  # 获取中文显示名。 
    return region_key, region_id, f"{region_name}({region_id})"  # 返回三元组供日志使用。 
def _preload_console_region_pages(regions):  # 购买前按所选地区访问 ECS 控制台页面。 
    if not CONSOLE_PRELOAD_ENABLED:  # 若配置关闭预热则直接跳过。 
        return ""  # 返回空表示不阻塞购买流程。 
    failures = []  # 收集访问失败的地区，避免部分页面未加载就进入购买。 
    checked = set()  # 去重，避免重复勾选同一地区时重复访问控制台页面。 
    for region in regions:  # 遍历前端勾选的地区。 
        region_key, region_id, label = _region_label(region)  # 解析地区标签和 regionId。 
        if region_id in checked:  # 已访问过该 regionId 则跳过。 
            continue  # 避免重复请求同一个控制台页面。 
        checked.add(region_id)  # 记录已处理地区。 
        url = CONSOLE_ECS_URLS_BY_REGION_ID.get(region_id)  # 读取对应 ECS 控制台 URL。 
        if not url:  # 未配置 URL 时视为预热失败，避免静默漏掉新增地区。 
            failures.append(f"{label}: 未配置控制台链接")  # 记录缺失配置。 
            continue  # 继续检查其他地区，最后统一返回。 
        _log(f"步骤: 购买前访问控制台地区页面 {label}")  # 输出地区页面预热开始日志。 
        last_error = ""  # 保存最后一次错误用于失败提示。 
        for attempt in range(1, max(1, CONSOLE_PRELOAD_RETRY_ATTEMPTS) + 1):  # 按配置次数重试。 
            try:  # 控制台页面只是预热访问，不使用浏览器自动化，避免引入额外依赖。 
                request = urllib.request.Request(url, headers={"User-Agent": "WaWaCloud-HUAWEI-Console-Preload/1.0"})  # 设置 UA 便于网关识别普通页面访问。 
                with urllib.request.urlopen(request, timeout=CONSOLE_PRELOAD_TIMEOUT_SECONDS) as response:  # 等待页面 HTTP 响应完成。 
                    body = response.read()  # 读取完整页面主体，确保不是刚连上就继续购买。 
                    status = int(getattr(response, "status", 200) or 200)  # 兼容不同 Python 版本的状态码字段。 
                if status >= 500 or not body:  # 服务端错误或空响应都不视为加载完成。 
                    raise RuntimeError(f"HTTP {status} 空响应" if not body else f"HTTP {status}")  # 抛出明确错误便于日志定位。 
                _log(f"步骤: 控制台地区页面已加载 {label} HTTP {status}")  # 输出页面加载完成日志。 
                break  # 成功后退出重试循环。 
            except (urllib.error.URLError, TimeoutError, OSError, RuntimeError) as exc:  # 捕获网络和超时异常。 
                last_error = str(exc)  # 记录本次失败原因。 
                if attempt >= max(1, CONSOLE_PRELOAD_RETRY_ATTEMPTS):  # 最后一次仍失败则记录汇总。 
                    failures.append(f"{label}: {last_error}")  # 记录地区失败明细。 
                    break  # 结束该地区重试。 
                _log(f"步骤: 控制台地区页面访问失败，重试 {attempt + 1}/{CONSOLE_PRELOAD_RETRY_ATTEMPTS} {label}: {last_error}")  # 输出重试日志。 
                time.sleep(CONSOLE_PRELOAD_RETRY_DELAY_SECONDS)  # 短等待后再试，减少瞬时网络抖动。 
    if failures:  # 任一地区未完成页面访问则阻止购买。 
        return "华为云控制台地区页面预热失败: " + "；".join(failures)  # 返回汇总错误。 
    return ""  # 全部页面访问完成。 
def _preflight_project_ids(regions):  # 购买前批量检查地区项目 ID 是否可获取。 
    missing = []  # 记录缺失地区，避免半路购买后才失败。 
    checked = set()  # 去重，避免重复选择同一地区时重复查询。 
    for region in regions:  # 遍历前端选择的地区。 
        region_key, region_id, label = _region_label(region)  # 获取地区标签。 
        if region_id in checked:  # 已检查过则跳过。 
            continue  # 避免重复调用 IAM。 
        checked.add(region_id)  # 记录已检查 regionId。 
        try:  # 尝试获取项目 ID。 
            get_project_id(region_id)  # 只做预检，不输出项目 ID。 
        except Exception as exc:  # 捕获缺失或权限异常。 
            missing.append((region_key, region_id, label, str(exc)))  # 保存错误明细。 
    if not missing:  # 所有地区均可获取项目 ID。 
        return ""  # 返回空表示预检通过。 
    labels = "、".join(item[2] for item in missing)  # 拼接缺失地区列表。 
    _log(f"步骤: 华为云地区项目预检失败 {labels}")  # 输出简短失败清单。 
    _log("步骤: 处理方式 请客户登录华为云控制台，依次切换这些地区并进入 ECS 或 VPC 页面完成初始化；如果仍失败，请确认该 IAM 用户拥有这些地区的项目权限。")  # 输出处理方式。 
    return f"华为云账号缺少地区项目或权限: {labels}"  # 返回汇总错误。 
def _print_summary(region_key, region_id, server_ip, aux_details, server_id="", note=""):  # 输出结果汇总信息的函数。 
    if not OUTPUT_SUMMARY:  # 若关闭结果输出则直接返回。 
        return  # 直接退出避免输出。 
    region_name = REGION_DISPLAY_NAMES.get(region_key, region_id)  # 获取地区中文名称，失败则回退 regionId。 
    prefix = _get_log_prefix()  # 获取线程级日志前缀。 
    def _emit(line):  # 定义统一输出函数以支持前缀。 
        if prefix:  # 若存在前缀则拼接输出。 
            print(f"[{prefix}] {line}")  # 输出带前缀的结果行。 
        else:  # 若无前缀则按原样输出。 
            print(line)  # 输出结果行用于展示。 
    _emit(f"地区:{region_name}")  # 输出地区信息。 
    if server_id:  # 若已获取到服务器 ID 则一并输出。 
        _emit(f"服务器ID:{server_id}")  # 输出服务器实例 ID。 
    _emit(f"服务器IP:{server_ip or 'N/A'}")  # 输出服务器公网 IP。 
    _emit(f"服务器密码:{PASSWORD}")  # 输出服务器密码。 
    if note:  # 若存在补充说明则一并输出。 
        _emit(f"说明:{note}")  # 输出说明信息帮助排查后续步骤。 
    _emit("cat > ip.txt <<'EOF'")  # 输出生成 ip.txt 的命令起始行。 
    for item in aux_details:  # 遍历辅助网卡详情列表。 
        _emit(f"{item['vlan_id']} {item['mac_address']} {item['ip_address']}")  # 输出 VLAN/MAC/IP 行。 
    _emit("EOF")  # 输出 heredoc 结束行。 
def run_flow(region_input):  # 执行完整购买流程的入口函数。 
    region_key = _resolve_region_key(region_input)  # 统一得到逻辑地区名以选择规格。 
    region_id = _resolve_region_id(region_key)  # 将逻辑地区名转换为 regionId。 
    _set_log_prefix(region_key)  # 设置当前线程的日志前缀为地区逻辑名。 
    server_id = ""  # 初始化服务器 ID 以便异常时输出部分结果。 
    server_ip = ""  # 初始化服务器公网 IP。 
    aux_details = []  # 初始化辅助网卡详情列表。 
    summary_emitted = False  # 标记是否已输出汇总信息。 
    try:  # 确保流程结束后清理日志前缀。 
        spec = _resolve_region_spec(region_key)  # 根据地区逻辑名与购买模式选择规格配置。
        if _is_twenty_purchase_mode():  # 20 规格输出明确日志便于主程序确认新拓扑已生效。
            _log(f"步骤: 20模式 已启用 flavor={spec['flavor']} 网卡=.10/.11 虚拟IP=.12/.13 辅助=.14-.29 EIP=20")
        if _is_delta_purchase_mode():  # x1.2u.2g 模式输出明确日志便于核对。
            _log("步骤: x1.2u.2g模式 已启用 flavor=x1.2u.2g disk=SAS size=10GB")  # 输出模式参数。
        _log(f"步骤: 创建VPC {region_id}")  # 输出创建 VPC 步骤日志。 
        vpc_id = create_vpc(region_id)  # 创建 VPC 并获取 VPC ID。 
        _log(f"步骤: 创建子网 {vpc_id}")  # 输出创建子网步骤日志。 
        subnet_id = create_subnet(region_id, vpc_id)  # 创建子网并获取子网 ID。 
        _log(f"步骤: 创建安全组 {region_id}")  # 输出创建安全组步骤日志。 
        sec_group_id = create_security_group(region_id, vpc_id)  # 创建本资源组独立安全组并获取 ID。 
        _log(f"步骤: 购买云服务器 {subnet_id}")  # 输出购买云服务器步骤日志。 
        server_id = purchase_server(region_id, subnet_id, sec_group_id, spec)  # 购买服务器并获取实例 ID。 
        _log(f"步骤: 创建辅助网卡 {server_id}")  # 输出创建辅助网卡步骤日志。 
        nic_ids = []  # 初始化辅助网卡 ID 列表。 
        if spec.get("aux_nic_count", 0) > 0:  # 判断是否需要辅助网卡。
            nic_ids.extend(create_aux_nic(region_id, server_id, subnet_id, sec_group_id, spec))  # 批量申请并记录辅助网卡 ID。
        main_port_id, secondary_port_id = get_server_ports(region_id, server_id, spec)  # 获取主/副网卡端口 ID。
        virtual_port_ids = []  # 初始化虚拟 IP 端口列表。
        if spec.get("virtual_ip_count", 0) > 0:  # 20 规格需要创建虚拟 IP，并绑定到主网卡允许地址对。
            virtual_port_ids = create_virtual_ips(region_id, subnet_id, sec_group_id, spec, main_port_id, spec.get("main_nic_ip"))  # 创建/复用虚拟 IP 端口。
        _log(f"步骤: 申请EIP {region_key}")  # 输出申请 EIP 步骤日志。
        eip_count = 1  # 初始化 EIP 数量，默认包含主网卡。
        if spec.get("extra_nic_count", 0) > 0:  # 若存在副网卡则增加一个 EIP。
            eip_count += 1  # 将副网卡的 EIP 计入总数。
        eip_count += int(spec.get("virtual_ip_count", 0) or 0)  # 20 规格虚拟 IP 每个绑定一个 EIP。
        eip_count += int(spec.get("aux_nic_count", 0) or 0)  # 加上辅助网卡数量对应的 EIP。
        eip_ids = allocate_eip(region_id, eip_count)  # 申请指定数量的 EIP 并返回 ID 列表。
        _log(f"步骤: 绑定EIP {len(eip_ids)}")  # 输出绑定 EIP 步骤日志。
        target_ports = [main_port_id]  # 初始化目标端口列表，先绑定主网卡。
        if secondary_port_id:  # 10IP/20规格第二个 EIP 绑定到 192.168.0.11 标准弹性网卡。
            target_ports.append(secondary_port_id)  # 加入副网卡端口。
        target_ports.extend(virtual_port_ids)  # 20规格随后绑定虚拟 IP 192.168.0.12 和 192.168.0.13。
        target_ports.extend(nic_ids)  # 最后绑定辅助弹性网卡，10IP 固定为 192.168.0.12-19，20规格固定为 192.168.0.14-29。
        if len(target_ports) < eip_count:  # 若端口数量仍不足则报错。 
            raise RuntimeError("EIP 数量大于可用网卡端口数量，请检查规格与规则")  # 提示检查配置。 
        for eip_id, port_id in zip(eip_ids, target_ports):  # 按顺序为端口绑定 EIP。 
            bind_eip(region_id, eip_id, port_id)  # 调用绑定接口将 EIP 绑定到端口。 
        try:  # 捕获公网 IP 查询异常，避免汇总信息完全丢失。 
            public_ips = get_public_ips_by_port(region_id, main_port_id)  # 查询主网卡绑定的公网 IP 列表。 
            server_ip = public_ips[0] if public_ips else ""  # 取第一个公网 IP 作为服务器 IP。 
        except Exception as exc:  # 查询公网 IP 失败时仅记录日志。 
            _log(f"步骤: 汇总查询公网IP失败 {exc}")  # 记录失败原因但不中断结果输出。 
        try:  # 捕获辅助网卡详情查询异常，避免汇总信息完全丢失。 
            aux_details = get_aux_nic_details(region_id, server_id, spec)  # 获取辅助网卡详情列表。 
        except Exception as exc:  # 查询辅助网卡详情失败时仅记录日志。 
            _log(f"步骤: 汇总查询辅助网卡失败 {exc}")  # 记录失败原因但不中断结果输出。 
        _print_summary(region_key, region_id, server_ip, aux_details, server_id=server_id)  # 输出结果汇总信息。 
        summary_emitted = True  # 标记已输出汇总信息。 
    except Exception as exc:  # 流程任意步骤失败时输出可用的部分结果。 
        if server_id and not summary_emitted:  # 若服务器已创建但汇总尚未输出，则补打一份部分结果。 
            _print_summary(
                region_key,
                region_id,
                server_ip,
                aux_details,
                server_id=server_id,
                note=f"后续步骤异常: {exc}",
            )  # 输出部分结果，避免前端结果区域空白。 
        raise  # 将原始异常继续抛出交给上层记录。 
    finally:  # 无论成功失败都清理日志前缀。 
        _set_log_prefix("")  # 清空线程日志前缀避免影响后续流程。 
def _run_all_regions():  # 批量运行所有地区的函数。 
    console_error = _preload_console_region_pages(ALL_REGION_KEYS)  # 购买前先逐个访问全部地区控制台页面。
    if console_error:  # 若控制台页面未完成加载则不进入购买。
        raise RuntimeError(console_error)  # 阻止后续购买，避免地区未初始化导致半路失败。
    preflight_error = _preflight_project_ids(ALL_REGION_KEYS)  # 先检查全部地区项目 ID。 
    if preflight_error:  # 若有地区缺少项目 ID。 
        raise RuntimeError(preflight_error)  # 直接中止，避免部分地区先购买。 
    for region_key in ALL_REGION_KEYS:  # 遍历所有地区逻辑名。 
        try:  # 捕获单个地区的异常以便继续。 
            _log(f"步骤: 开始地区 {region_key}")  # 输出开始处理地区的日志。 
            run_flow(region_key)  # 执行单个地区的完整流程。 
            _log(f"步骤: 完成地区 {region_key}")  # 输出完成处理地区的日志。 
        except Exception as exc:  # 捕获单个地区的异常。 
            _log(f"步骤: 地区异常 {region_key} {exc}")  # 输出地区错误日志。 
            if not CONTINUE_ON_ERROR:  # 若不允许继续则立即抛出。 
                raise  # 抛出异常中止批量流程。 
def _env_regions():  # 读取 API 子进程指定的地区列表。 
    raw = os.getenv("HUAWEI_REGIONS", "")  # 地区列表由 API 以逗号分隔传入。 
    return [item.strip() for item in raw.split(",") if item.strip()]  # 清理空白并过滤空值。 
def _run_selected_regions(regions):  # 并发运行 API 指定地区。
    _log("步骤: 自动购买预检开始")  # 输出预检开始，避免子进程启动后界面长时间无进度。
    console_error = _preload_console_region_pages(regions)  # 购买前先逐个访问勾选地区控制台页面。
    if console_error:  # 若控制台页面未完成加载。
        _log(f"步骤: 错误汇总 {console_error}")  # 输出汇总供 API 状态栏展示。
        return 7  # 返回非零退出码，避免继续购买。
    _log("步骤: 自动购买预检：检查地区项目ID")  # 项目 ID 查询可能受 IAM 响应影响，单独显示进度。
    preflight_error = _preflight_project_ids(regions)  # 先检查选择地区项目 ID。 
    if preflight_error:  # 若预检失败。 
        _log(f"步骤: 错误汇总 {preflight_error}")  # 输出汇总供 API 状态栏展示。 
        return 7  # 返回非零退出码，且不启动购买线程。 
    _log("步骤: 自动购买预检完成")  # 输出预检完成，后续才会进入地区并发购买。
    errors = []  # 记录每个地区的异常用于退出码和汇总日志。
    worker_raw = os.getenv("HUAWEI_REGION_WORKERS", "2").strip()  # 主程序传入的地区并发上限。
    try:
        worker_count = max(1, min(int(worker_raw or "2"), len(regions)))
    except ValueError:
        worker_count = min(2, len(regions))
    _log(f"步骤: 自动购买地区并发={worker_count}/{len(regions)}")

    def _run_region(region):  # 单个地区执行函数。
        try:  # 捕获地区异常，避免一个地区影响其他地区线程。
            _log(f"步骤: 开始地区 {region}")  # 输出开始日志。
            run_flow(region)  # 执行指定地区购买流程。
            _log(f"步骤: 完成地区 {region}")  # 输出完成日志。 
        except Exception as exc:  # 记录该地区异常。 
            _log(f"步骤: 地区异常 {region} {exc}")  # 输出异常日志。 
            return f"{region}:{exc}"  # 保存完整错误便于 API 汇总。
        return ""
    with concurrent.futures.ThreadPoolExecutor(max_workers=worker_count) as executor:
        future_map = {executor.submit(_run_region, region): region for region in regions}
        for future in concurrent.futures.as_completed(future_map):
            error_text = future.result()
            if error_text:
                errors.append(error_text)
    if errors:  # 若任一地区失败。 
        _log(f"步骤: 错误汇总 {'; '.join(errors)}")  # 输出完整错误供 API 日志读取。 
        return 7  # 返回非零退出码给 API 状态栏。 
    return 0  # 全部成功时返回 0。 
def main():  # 程序入口函数。 
    _ = (*get_runtime_ak_sk(), PROJECT_ID)  # 引用当前线程鉴权参数以便后续接入请求签名。 
    selected_regions = _env_regions()  # 优先读取 API 子进程指定地区。 
    if selected_regions:  # API 调用场景按前端选择地区执行。 
        exit_code = _run_selected_regions(selected_regions)  # 执行指定地区并收集退出码。 
        if exit_code:  # 若存在地区失败则以非零退出。 
            raise SystemExit(exit_code)  # 让 API 后台任务能识别失败状态。 
        return  # 指定地区执行完成后结束程序。 
    if RUN_ALL_REGIONS:  # 若开启批量运行则遍历所有地区。 
        _run_all_regions()  # 执行所有地区的流程。 
    else:  # 未开启批量运行则只运行默认地区。 
        run_flow(DEFAULT_REGION_ID)  # 使用默认区域运行流程。 
if __name__ == "__main__":  # 脚本直接执行时进入主入口。 
    main()  # 调用主入口启动流程。 
