/**
 * Bridge 包发布后通知服务
 *
 * 主干流程：读取 GitHub Actions 注入的 webhook URL 与密钥；两者均配置时，
 * 读取当前包名/版本并发送带 HMAC 签名的 JSON 通知；任一配置缺失时安全跳过。
 */
import axios from "axios";
import { createHmac } from "node:crypto";
import { readFile } from "node:fs/promises";
import path from "node:path";
import { fileURLToPath } from "node:url";
import { createLogger } from "../utils/logger.js";
const HOOK_URL_ENV = "BRIDGE_PACKAGE_ON_PUBLIC_HOOKS_URL";
const HOOK_SECRET_ENV = "BRIDGE_PACKAGE_ON_PUBLIC_HOOKS_SECRET";
const DEFAULT_TIMEOUT_MS = 10_000;
const publishHooksLogger = createLogger("bridge-package-publish-hooks");
function normalizeOptionalString(value) {
    if (value == null) {
        return undefined;
    }
    const normalized = String(value).trim();
    return normalized || undefined;
}
/**
 * 具体功能实现：只暴露 URL 是否已配置，避免 CI 日志泄露 token 型 URL。
 */
function describeHookUrl(url) {
    try {
        const parsed = new URL(url);
        return `${parsed.protocol}//${parsed.host}`;
    }
    catch {
        return "configured-url";
    }
}
/**
 * 具体功能实现：读取 package.json 中用于通知服务识别包版本的最小信息。
 */
export async function readBridgePackageInfo() {
    const packageJsonUrl = new URL("../../package.json", import.meta.url);
    const rawPackageJson = await readFile(packageJsonUrl, "utf-8");
    const packageJson = JSON.parse(rawPackageJson);
    const name = normalizeOptionalString(packageJson.name);
    const version = normalizeOptionalString(packageJson.version);
    if (!name || !version) {
        throw new Error("package.json must contain non-empty name and version fields");
    }
    return { name, version };
}
/**
 * 具体功能实现：构造稳定的发布通知负载，附带 GitHub Actions 上下文便于服务端审计。
 */
export function createBridgePackagePublishPayload(packageInfo, env = process.env, now = () => new Date()) {
    return {
        package: packageInfo.name,
        version: packageInfo.version,
        repository: normalizeOptionalString(env.GITHUB_REPOSITORY),
        ref: normalizeOptionalString(env.GITHUB_REF),
        sha: normalizeOptionalString(env.GITHUB_SHA),
        runId: normalizeOptionalString(env.GITHUB_RUN_ID),
        runNumber: normalizeOptionalString(env.GITHUB_RUN_NUMBER),
        publishedAt: now().toISOString(),
    };
}
/**
 * 具体功能实现：对实际发送的 JSON 字符串签名，保证服务端验签与请求体完全一致。
 */
export function createBridgePublishSignature(body, secret) {
    const digest = createHmac("sha256", secret).update(body, "utf-8").digest("hex");
    return `sha256=${digest}`;
}
/**
 * 主逻辑：根据环境变量决定跳过或发送发布通知；已配置 webhook 时失败会抛出，
 * 让 GitHub Actions 明确暴露“包已发布但通知失败”的状态。
 */
export async function notifyBridgePackagePublished(options = {}) {
    const env = options.env ?? process.env;
    const logger = options.logger ?? publishHooksLogger;
    const hookUrl = normalizeOptionalString(env[HOOK_URL_ENV]);
    const hookSecret = normalizeOptionalString(env[HOOK_SECRET_ENV]);
    if (!hookUrl && !hookSecret) {
        logger.info("Bridge package publish hook is not configured. Skipping notification.");
        return false;
    }
    if (!hookUrl || !hookSecret) {
        logger.warn(`Bridge package publish hook requires both ${HOOK_URL_ENV} and ${HOOK_SECRET_ENV}. Skipping notification.`);
        return false;
    }
    const packageInfo = options.packageInfo ?? (await readBridgePackageInfo());
    const payload = createBridgePackagePublishPayload(packageInfo, env, options.now);
    const body = JSON.stringify(payload);
    const signature = createBridgePublishSignature(body, hookSecret);
    const timestamp = String(Math.floor(Date.parse(payload.publishedAt) / 1000));
    const post = options.post ?? axios.post;
    logger.info(`Notifying bridge package publish hook for ${packageInfo.name}@${packageInfo.version} (${describeHookUrl(hookUrl)}).`);
    await post(hookUrl, body, {
        headers: {
            "Content-Type": "application/json",
            "X-Bridge-Signature": signature,
            "X-Bridge-Timestamp": timestamp,
        },
        timeout: DEFAULT_TIMEOUT_MS,
    });
    logger.info(`Bridge package publish hook notified for ${packageInfo.name}@${packageInfo.version}.`);
    return true;
}
const isCliEntry = process.argv[1]
    ? fileURLToPath(import.meta.url) === path.resolve(process.argv[1])
    : false;
if (isCliEntry) {
    notifyBridgePackagePublished().catch((error) => {
        publishHooksLogger.error("Failed to notify bridge package publish hook:", error instanceof Error ? error.message : String(error));
        process.exitCode = 1;
    });
}
