"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.TRANSIENT_NETWORK_RECOVERY_MAX_MS = exports.TRANSIENT_NETWORK_RECOVERY_BASE_MS = exports.WORKER_IDLE_TIMEOUT_RECOVERY_REASON = exports.TRANSIENT_NETWORK_RECOVERY_REASON = exports.MAX_FRESHNESS_PASSES = exports.WorkerCycleError = exports.EffectExecutionError = exports.PENDING_WAIT_HUMAN_PUBLICATION_KIND = exports.EFFECT_EXECUTION_ORDER = exports.EMPTY_FACTS = exports.resolveLinkedIssueIdFromPullRequest = void 0;
exports.collectManagedIssues = collectManagedIssues;
exports.cloneWorkflowStateSnapshot = cloneWorkflowStateSnapshot;
exports.resolvePreparationScannedInputCursor = resolvePreparationScannedInputCursor;
exports.readWorkerNeedsHumanReason = readWorkerNeedsHumanReason;
exports.matchesClaimedExecutionOwnership = matchesClaimedExecutionOwnership;
exports.compareExecutionPriority = compareExecutionPriority;
exports.loadSortedIssueComments = loadSortedIssueComments;
exports.resolveLinkedIssueIdFromPullRequestTimeline = resolveLinkedIssueIdFromPullRequestTimeline;
exports.hydratePullRequestIssueSourceBranchName = hydratePullRequestIssueSourceBranchName;
exports.buildIssueLogContext = buildIssueLogContext;
exports.loadPreExecutionIssueBootstrap = loadPreExecutionIssueBootstrap;
exports.loadPullRequestMonitorBootstrap = loadPullRequestMonitorBootstrap;
exports.loadWorkingInPrBootstrap = loadWorkingInPrBootstrap;
exports.returnLoggedSummary = returnLoggedSummary;
exports.resolveSingleAssignee = resolveSingleAssignee;
exports.resolveCurrentConsecutiveAiRuns = resolveCurrentConsecutiveAiRuns;
exports.resolveCurrentTotalAiRunHours = resolveCurrentTotalAiRunHours;
exports.resolveCurrentAiRunAccounting = resolveCurrentAiRunAccounting;
exports.isClaimedFreshnessSnapshot = isClaimedFreshnessSnapshot;
exports.areWorkflowStatesEqual = areWorkflowStatesEqual;
const canonical_workflow_state_1 = require("../../comments/canonical-workflow-state");
const workflow_update_1 = require("../../comments/workflow-update");
const control_plane_config_1 = require("../../config/control-plane-config");
const tracked_project_1 = require("../../core/tracked-project");
const issue_id_1 = require("../../issues/issue-id");
const pull_request_link_1 = require("../../issues/pull-request-link");
Object.defineProperty(exports, "resolveLinkedIssueIdFromPullRequest", { enumerable: true, get: function () { return pull_request_link_1.resolveLinkedIssueIdFromPullRequest; } });
const types_1 = require("../../platform/ticket-tracker/types");
const workflow_labels_1 = require("../../platform/ticket-tracker/workflow-labels");
const persisted_state_1 = require("../../workflows/state/persisted-state");
const workflow_timeline_scan_1 = require("../../workflows/workflow-timeline-scan");
const default_issue_workspace_manager_1 = require("../../workspaces/default-issue-workspace-manager");
const execution_ownership_1 = require("../execution-ownership");
const issue_logger_1 = require("../issue-logger");
const log_text_1 = require("../log-text");
const issue_branch_target_1 = require("./issue-branch-target");
const presentation_1 = require("./presentation");
const results_1 = require("./results");
exports.EMPTY_FACTS = {
    branchAheadOfBase: false,
    openPullRequestExists: false,
    pullRequestThreadId: null,
};
exports.EFFECT_EXECUTION_ORDER = [
    "ensure_pr",
    "sync_pr_assignees",
    "mark_pr_ready",
    "sync_pr_reviewers",
    "write_comment",
];
exports.PENDING_WAIT_HUMAN_PUBLICATION_KIND = "wait_human_write_comment";
class EffectExecutionError extends Error {
    result;
    pendingPublicationRecovery;
    constructor(message, result, cause, pendingPublicationRecovery) {
        super(message, { cause });
        this.result = result;
        this.pendingPublicationRecovery = pendingPublicationRecovery;
        this.name = "EffectExecutionError";
    }
}
exports.EffectExecutionError = EffectExecutionError;
class WorkerCycleError extends Error {
    seed;
    cause;
    constructor(seed, cause) {
        super(cause instanceof Error ? cause.message : String(cause), {
            cause: cause instanceof Error ? cause : undefined,
        });
        this.seed = seed;
        this.cause = cause;
        this.name = "WorkerCycleError";
    }
}
exports.WorkerCycleError = WorkerCycleError;
function collectManagedIssues(issues) {
    return issues.map((issue) => ({ issue, snapshot: issue.workflowState }));
}
function cloneWorkflowStateSnapshot(snapshot, status) {
    return {
        status: status ?? snapshot.status,
        rules: [...snapshot.rules],
    };
}
function resolvePreparationScannedInputCursor(input) {
    return (0, workflow_timeline_scan_1.scanWorkflowTimeline)({
        comments: input.comments,
        issueBody: input.latestIssue.kind === types_1.TRACKER_ITEM_KINDS.issue
            ? input.latestIssue.body
            : null,
        workflowState: input.workflowState,
    }).scannedInputCursor;
}
function readWorkerNeedsHumanReason(decision) {
    const reason = decision.needsHumanReason;
    return reason ?? null;
}
function matchesClaimedExecutionOwnership(input) {
    const expectedAssignee = resolveSingleAssignee(input.originalIssue);
    return ((expectedAssignee === null ||
        (input.latestIssue.assignees.length === 1 &&
            input.latestIssue.assignees[0] === expectedAssignee)) &&
        (0, execution_ownership_1.isExecutionOwnershipOwnedBy)(input.currentExecutionOwnership, input.expectedExecutionOwnership));
}
exports.MAX_FRESHNESS_PASSES = 3;
exports.TRANSIENT_NETWORK_RECOVERY_REASON = "transient_network_error";
exports.WORKER_IDLE_TIMEOUT_RECOVERY_REASON = "worker_idle_timeout";
exports.TRANSIENT_NETWORK_RECOVERY_BASE_MS = 30_000;
exports.TRANSIENT_NETWORK_RECOVERY_MAX_MS = 15 * 60 * 1_000;
function resolvePriorityRank(workflowState) {
    return workflowState?.priorityRank ?? null;
}
function compareIssueIds(leftIssueId, rightIssueId) {
    const leftNumericId = (0, issue_id_1.parseNumericIssueId)(leftIssueId);
    const rightNumericId = (0, issue_id_1.parseNumericIssueId)(rightIssueId);
    if (leftNumericId !== null && rightNumericId !== null) {
        return leftNumericId - rightNumericId;
    }
    return leftIssueId.localeCompare(rightIssueId);
}
function compareExecutionPriority(left, right) {
    const leftPriorityRank = resolvePriorityRank(left.workflowState);
    const rightPriorityRank = resolvePriorityRank(right.workflowState);
    if (leftPriorityRank === null) {
        if (rightPriorityRank !== null) {
            return 1;
        }
    }
    else if (rightPriorityRank === null) {
        return -1;
    }
    else if (leftPriorityRank !== rightPriorityRank) {
        return leftPriorityRank - rightPriorityRank;
    }
    return compareIssueIds(left.issueId, right.issueId);
}
async function loadSortedIssueComments(ticketTracker, issueId, options) {
    return (0, workflow_timeline_scan_1.sortTimelineComments)(await ticketTracker.listComments(issueId, {
        timeline: options?.timeline ?? "full",
    }));
}
async function resolveLinkedIssueIdFromPullRequestTimeline(ticketTracker, issue) {
    if (issue.kind !== types_1.TRACKER_ITEM_KINDS.pullRequest) {
        return null;
    }
    const bodyIssueId = (0, pull_request_link_1.resolveLinkedIssueIdFromPullRequest)({
        body: issue.body,
    });
    if (bodyIssueId !== null) {
        return bodyIssueId;
    }
    return (0, pull_request_link_1.resolveLinkedIssueIdFromPullRequest)({ body: issue.body }, await loadSortedIssueComments(ticketTracker, issue.id, {
        timeline: "issue-only",
    }));
}
async function hydratePullRequestIssueSourceBranchName(ticketTracker, issue) {
    if (issue.kind !== types_1.TRACKER_ITEM_KINDS.pullRequest ||
        issue.sourceBranchName?.trim()) {
        return issue;
    }
    const hydratedIssue = await ticketTracker.getIssue(issue.id);
    return hydratedIssue.kind === types_1.TRACKER_ITEM_KINDS.pullRequest
        ? hydratedIssue
        : issue;
}
function buildIssueLogContext(trackedProject, issue, logHomeDirectory) {
    const responseLanguage = trackedProject.i18n.defaultLanguage;
    return {
        responseLanguage,
        logger: new issue_logger_1.IssueLogger((0, tracked_project_1.toTrackedProjectRef)(trackedProject), issue.id, {
            homeDirectory: logHomeDirectory,
            locale: responseLanguage,
        }),
    };
}
async function loadPreExecutionIssueBootstrap(input) {
    const comments = await loadSortedIssueComments(input.context.ticketTracker, input.issue.id, { timeline: "issue-only" });
    const issueContext = {
        ...input.context,
        config: (0, control_plane_config_1.resolveIssueEffectiveConfigFromComments)(input.context.config, comments, undefined, { issueBody: input.issue.body }),
    };
    const workflowLabels = issueContext.config.ticketTracker.workflowLabels;
    const { logger, responseLanguage } = buildIssueLogContext(issueContext.config, input.issue, issueContext.logHomeDirectory);
    return {
        comments,
        issueContext,
        logger,
        responseLanguage,
        workflowLabels,
    };
}
async function loadPullRequestMonitorBootstrap(input) {
    const bootstrap = await loadPreExecutionIssueBootstrap({
        context: input.context,
        issue: input.executable.issue,
    });
    const issueForBranch = await hydratePullRequestIssueSourceBranchName(bootstrap.issueContext.ticketTracker, input.executable.issue);
    const branchName = issueForBranch.sourceBranchName ??
        (0, default_issue_workspace_manager_1.resolveIssueBranchName)(bootstrap.issueContext.config.branchPrefix, issueForBranch);
    const canonicalState = (0, canonical_workflow_state_1.resolveCanonicalWorkflowStateComment)(bootstrap.comments);
    const pullRequest = input.executable.issue.kind === types_1.TRACKER_ITEM_KINDS.pullRequest &&
        canonicalState.kind === "found"
        ? (0, results_1.filterPullRequestByBase)(await bootstrap.issueContext.repositoryHost.findPullRequestByBranch(branchName), (0, issue_branch_target_1.resolveIssueRunBaseBranch)(canonicalState.workflowState))
        : null;
    const pullRequestNumber = input.executable.issue.pullRequestNumber ?? null;
    const automationState = pullRequestNumber === null
        ? null
        : await bootstrap.issueContext.repositoryHost.getPullRequestAutomationState(pullRequestNumber);
    await bootstrap.logger.appendRunStart({
        runKind: "preflight_handoff",
        issue: input.executable.issue,
        currentLabels: (0, workflow_labels_1.projectWorkflowLabelNames)(bootstrap.workflowLabels, input.executable.issue.workflowState),
        pullRequestUrl: automationState?.url ?? pullRequest?.url ?? null,
    });
    return {
        ...bootstrap,
        issueForBranch,
        branchName,
        pullRequest,
        automationState,
    };
}
async function loadWorkingInPrBootstrap(input) {
    const bootstrap = await loadPreExecutionIssueBootstrap({
        context: input.context,
        issue: input.executable.issue,
    });
    const branchName = (0, default_issue_workspace_manager_1.resolveIssueBranchName)(bootstrap.issueContext.config.branchPrefix, input.executable.issue);
    const canonicalState = (0, canonical_workflow_state_1.resolveCanonicalWorkflowStateComment)(bootstrap.comments);
    const pullRequest = canonicalState.kind === "found"
        ? (0, results_1.filterPullRequestByBase)(await bootstrap.issueContext.repositoryHost.findPullRequestByBranch(branchName), (0, issue_branch_target_1.resolveIssueRunBaseBranch)(canonicalState.workflowState))
        : null;
    await bootstrap.logger.appendRunStart({
        runKind: "preflight_handoff",
        issue: input.executable.issue,
        currentLabels: (0, workflow_labels_1.projectWorkflowLabelNames)(bootstrap.workflowLabels, input.executable.issue.workflowState),
        pullRequestUrl: pullRequest?.url ?? null,
    });
    return {
        ...bootstrap,
        branchName,
        pullRequest,
    };
}
async function returnLoggedSummary(logger, summary) {
    await logger.appendSection((0, log_text_1.issueLogSection)("finalSummary"), (0, presentation_1.renderCliSummary)(summary, logger.locale));
    return summary;
}
function resolveSingleAssignee(issue) {
    return issue.assignees.length === 1 ? (issue.assignees[0] ?? null) : null;
}
function resolveCurrentConsecutiveAiRuns(comments, latestIssue) {
    return resolveCurrentAiRunAccounting(comments, latestIssue).consecutiveAiRuns;
}
function resolveCurrentTotalAiRunHours(comments, latestIssue) {
    return resolveCurrentAiRunAccounting(comments, latestIssue).totalAiRunHours;
}
function resolveCurrentAiRunAccounting(comments, latestIssue) {
    const resolution = (0, canonical_workflow_state_1.resolveCanonicalWorkflowStateComment)(comments);
    if (resolution.kind === "found") {
        if (latestIssue !== undefined &&
            latestIssue !== null &&
            (0, persisted_state_1.isHumanInputResumeProjection)({
                snapshot: latestIssue.workflowState,
                workflowState: resolution.workflowState,
            })) {
            return {
                consecutiveAiRuns: 0,
                totalAiRunHours: 0,
            };
        }
        if ((0, workflow_timeline_scan_1.hasActionableWorkflowCommentAfterCursor)(comments, resolution.workflowState.lastScannedCommentCursor ?? null)) {
            return {
                consecutiveAiRuns: 0,
                totalAiRunHours: 0,
            };
        }
        return {
            consecutiveAiRuns: resolution.workflowState.consecutiveAiRuns,
            totalAiRunHours: resolution.workflowState.totalAiRunHours,
        };
    }
    return {
        consecutiveAiRuns: (0, workflow_update_1.findCurrentConsecutiveAiRuns)(comments),
        totalAiRunHours: 0,
    };
}
function isClaimedFreshnessSnapshot(aiRunningSnapshot, latestIssue) {
    return (latestIssue.isOpen &&
        areWorkflowStatesEqual(latestIssue.workflowState, aiRunningSnapshot));
}
function areWorkflowStatesEqual(left, right) {
    if (left.status !== right.status ||
        left.rules.length !== right.rules.length) {
        return false;
    }
    const leftRules = [...left.rules].sort();
    const rightRules = [...right.rules].sort();
    return leftRules.every((rule, index) => rule === rightRules[index]);
}
