import fs from "node:fs/promises";
import path from "node:path";
import { randomUUID } from "node:crypto";
import axios from "axios";
import { getRuntimeHomeDir, resolveSchedulerBaseUrlFrom } from "../config.js";
import { getRuntimeAccessToken, loadRuntimeBinding, normalizeSchedulerBaseUrl, } from "./runtime-binding.js";
import { createLogger } from "../utils/logger.js";
const log = createLogger("bridge-lifecycle");
function lifecycleStateFile() {
    return path.join(getRuntimeHomeDir(), ".agentswork", "runtime-bridge", "lifecycle-state.json");
}
function normalizeText(value) {
    const normalized = String(value || "").trim();
    return normalized || undefined;
}
async function loadLifecycleState() {
    try {
        const raw = await fs.readFile(lifecycleStateFile(), "utf8");
        const parsed = JSON.parse(raw);
        return { operations: Array.isArray(parsed.operations) ? parsed.operations : [] };
    }
    catch {
        return { operations: [] };
    }
}
async function saveLifecycleState(state) {
    const file = lifecycleStateFile();
    await fs.mkdir(path.dirname(file), { recursive: true });
    await fs.writeFile(file, `${JSON.stringify(state, null, 2)}\n`, {
        encoding: "utf8",
        mode: 0o600,
    });
}
export function createBridgeLifecycleOperation(input) {
    const now = new Date().toISOString();
    const schedulerBaseUrl = normalizeSchedulerBaseUrl(input.schedulerBaseUrl) ||
        resolveSchedulerBaseUrlFrom(undefined).url;
    return {
        operationId: randomUUID(),
        operationType: input.operationType,
        status: input.status || "accepted",
        requestedByUserId: input.requestedByUserId,
        requestedAt: now,
        updatedAt: now,
        schedulerBaseUrl,
        runtimeBridgeBaseUrl: normalizeText(input.runtimeBridgeBaseUrl),
        message: input.message,
    };
}
export async function upsertBridgeLifecycleOperation(operation) {
    const state = await loadLifecycleState();
    const nextOperations = state.operations.filter((item) => item.operationId !== operation.operationId);
    nextOperations.push({ ...operation, updatedAt: new Date().toISOString() });
    await saveLifecycleState({ operations: nextOperations });
}
export async function removeBridgeLifecycleOperation(operationId) {
    const state = await loadLifecycleState();
    await saveLifecycleState({
        operations: state.operations.filter((item) => item.operationId !== operationId),
    });
}
function shouldDeliver(operation) {
    return ["succeeded", "failed", "startup-confirmed"].includes(operation.status);
}
async function sendLifecycleNotification(operation) {
    const schedulerBaseUrl = normalizeSchedulerBaseUrl(operation.schedulerBaseUrl) ||
        normalizeSchedulerBaseUrl(loadRuntimeBinding().schedulerBaseUrl) ||
        resolveSchedulerBaseUrlFrom(undefined).url;
    const token = getRuntimeAccessToken(operation.requestedByUserId, schedulerBaseUrl);
    if (!token) {
        throw new Error("runtime access token is missing");
    }
    await axios.post(`${schedulerBaseUrl}/api/runtime/callback/bridge-lifecycle`, {
        operationId: operation.operationId,
        operationType: operation.operationType,
        status: operation.status,
        requestedByUserId: operation.requestedByUserId,
        message: operation.message,
        error: operation.error,
        runtimeBridgeBaseUrl: operation.runtimeBridgeBaseUrl,
    }, { headers: { "X-Runtime-Token": token } });
}
/**
 * 投递 Bridge 生命周期通知。
 * 主流程：把已完成操作回调调度中心；已接收的操作从本地状态移除，失败则保留待下次启动重试。
 */
export async function deliverPendingBridgeLifecycleNotifications() {
    const state = await loadLifecycleState();
    for (const operation of state.operations) {
        const operationToDeliver = operation.operationType === "restart" && operation.status === "accepted"
            ? {
                ...operation,
                status: "startup-confirmed",
                message: operation.message || "Bridge 已在收到重启请求后完成本次启动。",
            }
            : operation;
        if (!shouldDeliver(operationToDeliver)) {
            continue;
        }
        try {
            await sendLifecycleNotification(operationToDeliver);
            await removeBridgeLifecycleOperation(operation.operationId);
            log.info(`[bridge-lifecycle] notification delivered: ${operation.operationId}`);
        }
        catch (error) {
            const err = error;
            log.warn(`[bridge-lifecycle] notification delivery failed: ${operation.operationId}, ${err.message}`);
        }
    }
}
