"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.readNetworkRecoveryState = readNetworkRecoveryState;
exports.listRepoNetworkRecoveryEntries = listRepoNetworkRecoveryEntries;
exports.upsertNetworkRecoveryEntry = upsertNetworkRecoveryEntry;
exports.removeNetworkRecoveryEntry = removeNetworkRecoveryEntry;
const promises_1 = require("node:fs/promises");
const node_path_1 = __importDefault(require("node:path"));
const zod_1 = require("zod");
const file_readers_1 = require("./file-readers");
const paths_1 = require("./paths");
const workflowStateSnapshotRecoverySchema = zod_1.z
    .object({
    status: zod_1.z.string().min(1),
    rules: zod_1.z.array(zod_1.z.string()),
})
    .passthrough();
const trackerIssueRecoverySchema = zod_1.z
    .object({
    id: zod_1.z.string().min(1),
    displayId: zod_1.z.string().min(1),
    title: zod_1.z.string(),
    url: zod_1.z.string(),
    isOpen: zod_1.z.boolean(),
    workflowState: workflowStateSnapshotRecoverySchema,
})
    .passthrough();
const issueTransitionStateRecoverySchema = zod_1.z
    .object({
    issue: trackerIssueRecoverySchema,
    previousSnapshot: workflowStateSnapshotRecoverySchema,
    nextSnapshot: workflowStateSnapshotRecoverySchema,
    requestedOutcome: zod_1.z.string().min(1),
    finalOutcome: zod_1.z.string().min(1),
    summary: zod_1.z.string(),
    facts: zod_1.z
        .object({
        branchAheadOfBase: zod_1.z.boolean(),
        openPullRequestExists: zod_1.z.boolean(),
        pullRequestThreadId: zod_1.z.string().nullable(),
    })
        .passthrough(),
    branchName: zod_1.z.string(),
    baseBranch: zod_1.z.string(),
    pullRequestThreadId: zod_1.z.string().nullable(),
    pullRequestUrl: zod_1.z.string().nullable(),
    responseLanguage: zod_1.z.string().min(1),
    presentation: zod_1.z
        .object({
        cliNext: zod_1.z.string(),
    })
        .passthrough(),
})
    .passthrough();
const workflowPublishRequestRecoverySchema = zod_1.z
    .object({
    target: zod_1.z.object({ kind: zod_1.z.string().min(1) }).passthrough(),
    workflowState: zod_1.z
        .object({
        version: zod_1.z.number().int(),
    })
        .passthrough()
        .nullable(),
    commentCursorPolicy: zod_1.z.object({ mode: zod_1.z.string().min(1) }).passthrough(),
    responseLanguage: zod_1.z.string().min(1),
})
    .passthrough();
const networkRecoveryEntrySchema = zod_1.z.object({
    trackedProjectKey: zod_1.z.string().min(1),
    issueId: zod_1.z.string().min(1),
    reason: zod_1.z.enum(["transient_network_error", "worker_idle_timeout"]),
    attemptCount: zod_1.z.number().int().positive(),
    nextRetryAt: zod_1.z.string().min(1),
    lastError: zod_1.z.string().min(1),
    updatedAt: zod_1.z.string().min(1),
    pendingPublication: zod_1.z
        .object({
        kind: zod_1.z.literal("wait_human_write_comment"),
        status: zod_1.z.enum(["scheduled", "blocked"]),
        blockedReason: zod_1.z
            .enum(["issue_closed", "precondition_failed", "state_changed"])
            .optional(),
        blockedAt: zod_1.z.string().min(1).optional(),
        transitionState: zod_1.z.custom((value) => issueTransitionStateRecoverySchema.safeParse(value).success),
        publishRequest: zod_1.z.custom((value) => workflowPublishRequestRecoverySchema.safeParse(value).success),
        effectResult: zod_1.z.object({
            commentUrl: zod_1.z.string().nullable(),
            pullRequestUrl: zod_1.z.string().nullable(),
            pullRequestThreadId: zod_1.z.string().nullable(),
        }),
        createdAt: zod_1.z.string().min(1),
    })
        .optional(),
});
const networkRecoveryStateSchema = zod_1.z.object({
    version: zod_1.z.literal(1),
    entries: zod_1.z.array(networkRecoveryEntrySchema),
});
const EMPTY_STATE = {
    version: 1,
    entries: [],
};
async function readNetworkRecoveryState(homeDirectory) {
    const statePath = (0, paths_1.getNetworkRecoveryStatePath)(homeDirectory);
    const text = await (0, file_readers_1.readTextFileIfExists)(statePath);
    if (text === null) {
        return createEmptyNetworkRecoveryState();
    }
    let parsed;
    try {
        parsed = JSON.parse(text);
    }
    catch {
        return createEmptyNetworkRecoveryState();
    }
    if (!isNetworkRecoveryStateEnvelope(parsed)) {
        return createEmptyNetworkRecoveryState();
    }
    return {
        version: 1,
        entries: parsed.entries.flatMap((entry) => {
            const result = networkRecoveryEntrySchema.safeParse(entry);
            return result.success ? [result.data] : [];
        }),
    };
}
function isNetworkRecoveryStateEnvelope(value) {
    if (typeof value !== "object" || value === null || Array.isArray(value)) {
        return false;
    }
    const candidate = value;
    return candidate.version === 1 && Array.isArray(candidate.entries);
}
function createEmptyNetworkRecoveryState() {
    return {
        ...EMPTY_STATE,
        entries: [],
    };
}
async function listRepoNetworkRecoveryEntries(trackedProjectKey, homeDirectory) {
    const state = await readNetworkRecoveryState(homeDirectory);
    return state.entries.filter((entry) => entry.trackedProjectKey === trackedProjectKey);
}
async function upsertNetworkRecoveryEntry(entry, homeDirectory) {
    const state = await readNetworkRecoveryState(homeDirectory);
    const normalized = networkRecoveryEntrySchema.parse(entry);
    const entries = state.entries.filter((candidate) => !(candidate.trackedProjectKey === normalized.trackedProjectKey &&
        candidate.issueId === normalized.issueId &&
        candidate.reason === normalized.reason));
    entries.push(normalized);
    await writeNetworkRecoveryState({
        version: 1,
        entries,
    }, homeDirectory);
}
async function removeNetworkRecoveryEntry(trackedProjectKey, issueId, reason, homeDirectory) {
    const state = await readNetworkRecoveryState(homeDirectory);
    const entries = state.entries.filter((entry) => !(entry.trackedProjectKey === trackedProjectKey &&
        entry.issueId === issueId &&
        (reason === undefined || entry.reason === reason)));
    if (entries.length === state.entries.length) {
        return;
    }
    await writeNetworkRecoveryState({
        version: 1,
        entries,
    }, homeDirectory);
}
async function writeNetworkRecoveryState(state, homeDirectory) {
    const statePath = (0, paths_1.getNetworkRecoveryStatePath)(homeDirectory);
    await (0, promises_1.mkdir)(node_path_1.default.dirname(statePath), { recursive: true });
    const normalized = networkRecoveryStateSchema.parse(state);
    await (0, promises_1.writeFile)(statePath, `${JSON.stringify(normalized, null, 2)}\n`, "utf8");
}
