"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.TRANSIENT_NETWORK_HANDOFF_ATTEMPT_COUNT = void 0;
exports.loadFreshnessSnapshot = loadFreshnessSnapshot;
exports.renderFreshnessRefreshSection = renderFreshnessRefreshSection;
exports.renderFreshnessRerunSection = renderFreshnessRerunSection;
exports.renderPublishAbortedSection = renderPublishAbortedSection;
exports.buildInterruptedSummary = buildInterruptedSummary;
exports.scheduleTransientNetworkRecovery = scheduleTransientNetworkRecovery;
exports.renderWorkerAttemptLabel = renderWorkerAttemptLabel;
const store_1 = require("../../auth-profiles/store");
const canonical_workflow_state_1 = require("../../comments/canonical-workflow-state");
const control_plane_config_1 = require("../../config/control-plane-config");
const network_recovery_state_1 = require("../../core/network-recovery-state");
const tracked_project_1 = require("../../core/tracked-project");
const catalog_1 = require("../../i18n/catalog");
const provider_resolution_1 = require("../../platform/provider-resolution");
const constants_1 = require("../constants");
const issue_logger_1 = require("../issue-logger");
const log_text_1 = require("../log-text");
const presentation_1 = require("./presentation");
const results_1 = require("./results");
const shared_1 = require("./shared");
exports.TRANSIENT_NETWORK_HANDOFF_ATTEMPT_COUNT = 3;
async function loadFreshnessSnapshot(ticketTracker, issueId) {
    const [latestIssue, comments] = await Promise.all([
        ticketTracker.getIssue(issueId),
        (0, shared_1.loadSortedIssueComments)(ticketTracker, issueId),
    ]);
    const canonicalResolution = (0, canonical_workflow_state_1.resolveCanonicalWorkflowStateComment)(comments);
    const latestScannedCommentCursor = (0, shared_1.resolvePreparationScannedInputCursor)({
        comments,
        latestIssue,
        workflowState: canonicalResolution.kind === "found"
            ? canonicalResolution.workflowState
            : null,
    });
    const aiRunAccounting = (0, shared_1.resolveCurrentAiRunAccounting)(comments, latestIssue);
    return {
        latestIssue,
        comments,
        cursor: latestScannedCommentCursor,
        currentConsecutiveAiRuns: aiRunAccounting.consecutiveAiRuns,
        currentTotalAiRunHours: aiRunAccounting.totalAiRunHours,
    };
}
function renderFreshnessRefreshSection(input) {
    return [
        (0, log_text_1.issueLogField)("pass", `${input.pass}/${input.maxPasses}`),
        (0, log_text_1.issueLogField)("note", input.note),
        (0, log_text_1.issueLogField)("issueOpen", (0, log_text_1.formatLogBoolean)(input.latestIssue.isOpen)),
        (0, log_text_1.issueLogField)("workflow", (0, presentation_1.formatWorkflowState)(input.workflowLabels, input.latestIssue.workflowState)),
        (0, log_text_1.issueLogField)("cursor", (0, issue_logger_1.formatNullable)(formatWorkflowCommentCursor(input.cursor))),
        (0, log_text_1.issueLogField)("commentCount", input.commentCount),
        (0, log_text_1.issueLogField)("currentConsecutiveAiRuns", input.currentConsecutiveAiRuns),
        (0, log_text_1.issueLogField)("currentTotalAiRunHours", input.currentTotalAiRunHours),
    ].join("\n");
}
function renderFreshnessRerunSection(input) {
    return [
        (0, log_text_1.issueLogField)("pass", `${input.pass}/${input.maxPasses}`),
        (0, log_text_1.issueLogField)("reason", input.reason),
        (0, log_text_1.issueLogField)("cursorBefore", (0, issue_logger_1.formatNullable)(formatWorkflowCommentCursor(input.cursorBefore))),
        (0, log_text_1.issueLogField)("cursorAfter", (0, issue_logger_1.formatNullable)(formatWorkflowCommentCursor(input.cursorAfter))),
    ].join("\n");
}
function renderPublishAbortedSection(input) {
    return [
        (0, log_text_1.issueLogField)("reason", input.reason),
        (0, log_text_1.issueLogField)("pass", `${input.pass}/${input.maxPasses}`),
        (0, log_text_1.issueLogField)("cursorBefore", (0, issue_logger_1.formatNullable)(formatWorkflowCommentCursor(input.cursorBefore))),
        (0, log_text_1.issueLogField)("cursorAfter", (0, issue_logger_1.formatNullable)(formatWorkflowCommentCursor(input.cursorAfter))),
        (0, log_text_1.issueLogField)("claimedWorkflow", (0, presentation_1.formatWorkflowState)(input.workflowLabels, input.claimedSnapshot)),
        (0, log_text_1.issueLogField)("currentWorkflow", (0, presentation_1.formatWorkflowState)(input.workflowLabels, input.currentSnapshot)),
    ].join("\n");
}
function formatWorkflowCommentCursor(cursor) {
    return cursor === null ? null : `${cursor.commentId}@${cursor.createdAt}`;
}
function buildInterruptedSummary(issue, reason, responseLanguage) {
    const headline = reason === "new-comment"
        ? (0, catalog_1.translate)(responseLanguage, "run.summary.interrupted.newComment", {
            issueDisplayId: issue.displayId,
        })
        : (0, catalog_1.translate)(responseLanguage, "run.summary.interrupted.stateChanged", {
            issueDisplayId: issue.displayId,
        });
    const nextStep = reason === "new-comment"
        ? (0, catalog_1.translate)(responseLanguage, "run.summary.interrupted.next.newComment")
        : (0, catalog_1.translate)(responseLanguage, "run.summary.interrupted.next.stateChanged");
    return (0, results_1.buildRunCliSummary)({
        issue,
        outcome: constants_1.RUN_ISSUE_OUTCOMES.interrupted,
        headline,
        commentUrl: null,
        prUrl: null,
        nextStep,
        interruptReason: reason,
    });
}
async function scheduleTransientNetworkRecovery(context, logger, issue, effectResult, error) {
    const trackedProjectKey = (0, provider_resolution_1.getTrackedProjectKey)((0, tracked_project_1.toTrackedProjectRef)(context.config));
    const existingEntry = (await (0, network_recovery_state_1.listRepoNetworkRecoveryEntries)(trackedProjectKey, context.logHomeDirectory)).find((entry) => entry.issueId === issue.id &&
        entry.reason === shared_1.TRANSIENT_NETWORK_RECOVERY_REASON);
    const attemptCount = (existingEntry?.attemptCount ?? 0) + 1;
    const retryAt = new Date(Date.now() + calculateTransientNetworkRecoveryDelayMs(attemptCount)).toISOString();
    const lastError = (0, results_1.buildFailureSummary)(error);
    if (attemptCount >= exports.TRANSIENT_NETWORK_HANDOFF_ATTEMPT_COUNT) {
        await (0, network_recovery_state_1.removeNetworkRecoveryEntry)(trackedProjectKey, issue.id, shared_1.TRANSIENT_NETWORK_RECOVERY_REASON, context.logHomeDirectory);
        await logger.appendSection((0, log_text_1.issueLogSection)("networkRecoveryEscalated"), [
            (0, log_text_1.issueLogField)("reason", shared_1.TRANSIENT_NETWORK_RECOVERY_REASON),
            (0, log_text_1.issueLogField)("attemptCount", attemptCount),
            (0, log_text_1.issueLogField)("retryAt", retryAt),
            (0, log_text_1.issueLogField)("lastError", lastError),
        ].join("\n"));
        return {
            kind: "handoff",
            attemptCount,
            retryAt,
            lastError,
        };
    }
    await (0, network_recovery_state_1.upsertNetworkRecoveryEntry)({
        trackedProjectKey,
        issueId: issue.id,
        reason: shared_1.TRANSIENT_NETWORK_RECOVERY_REASON,
        attemptCount,
        nextRetryAt: retryAt,
        lastError,
        updatedAt: new Date().toISOString(),
    }, context.logHomeDirectory);
    await logger.appendSection((0, log_text_1.issueLogSection)("networkRecoveryScheduled"), [
        (0, log_text_1.issueLogField)("reason", shared_1.TRANSIENT_NETWORK_RECOVERY_REASON),
        (0, log_text_1.issueLogField)("attemptCount", attemptCount),
        (0, log_text_1.issueLogField)("retryAt", retryAt),
    ].join("\n"));
    return {
        kind: "retry",
        attemptCount,
        retryAt,
        lastError,
        summary: buildTransientNetworkRecoverySummary(issue, effectResult, context.config.i18n.defaultLanguage, retryAt),
    };
}
function buildTransientNetworkRecoverySummary(issue, effectResult, responseLanguage, retryAt) {
    return (0, results_1.buildRunCliSummary)({
        issue,
        outcome: constants_1.RUN_ISSUE_OUTCOMES.failed,
        responseLanguage,
        summary: (0, catalog_1.translate)(responseLanguage, "run.summary.transientNetwork"),
        commentUrl: effectResult.commentUrl,
        prUrl: effectResult.pullRequestUrl,
        pullRequestThreadId: effectResult.pullRequestThreadId,
        nextStep: (0, catalog_1.translate)(responseLanguage, "run.summary.transientNetwork.next"),
        deferredReason: shared_1.TRANSIENT_NETWORK_RECOVERY_REASON,
        cooldownUntil: retryAt,
    });
}
function calculateTransientNetworkRecoveryDelayMs(attemptCount) {
    return Math.min(shared_1.TRANSIENT_NETWORK_RECOVERY_BASE_MS * 2 ** Math.max(attemptCount - 1, 0), shared_1.TRANSIENT_NETWORK_RECOVERY_MAX_MS);
}
function renderWorkerAttemptLabel(workerName) {
    return (0, control_plane_config_1.isBuiltInWorkerName)(workerName)
        ? (0, store_1.formatAuthProvider)(workerName)
        : workerName;
}
