"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.buildWaitHumanTransitionState = buildWaitHumanTransitionState;
exports.buildSuccessfulTransitionState = buildSuccessfulTransitionState;
exports.createFailureSeed = createFailureSeed;
const control_plane_config_1 = require("../../config/control-plane-config");
const issue_completion_1 = require("../../config/issue-completion");
const types_1 = require("../../platform/ticket-tracker/types");
const types_2 = require("../../platform/workflow-state/types");
const constants_1 = require("../../worker/constants");
const types_3 = require("../../worker/types");
const assignee_resolution_1 = require("../../workflows/assignee-resolution");
const publisher_events_1 = require("../../workflows/publisher-events");
const recurring_1 = require("../../workflows/recurring");
const default_issue_workspace_manager_1 = require("../../workspaces/default-issue-workspace-manager");
const execution_ownership_1 = require("../execution-ownership");
const ai_run_accounting_1 = require("./ai-run-accounting");
const followup_recommendation_state_1 = require("./followup-recommendation-state");
const issue_branch_target_1 = require("./issue-branch-target");
const needs_human_1 = require("./needs-human");
const presentation_1 = require("./presentation");
const results_1 = require("./results");
const run_limit_policy_1 = require("./run-limit-policy");
const run_state_helpers_1 = require("./run-state-helpers");
const transition_presentation_1 = require("./transition-presentation");
function buildWaitHumanTransitionState(input) {
    const nextSnapshot = {
        status: types_2.WORKFLOW_STATUSES.aiNeedsHuman,
        rules: [...input.readySnapshot.rules],
    };
    const presentation = (0, transition_presentation_1.buildTransitionPresentation)({
        config: input.config,
        issue: input.issue,
        finalOutcome: constants_1.WORKER_OUTCOMES.waitHuman,
        facts: input.facts,
        summary: input.summary,
        comment: null,
        result: null,
        consecutiveAiRuns: input.consecutiveAiRuns,
        responseLanguage: input.responseLanguage,
        workflowState: input.workflowState,
        handoffToPr: false,
        handoffPullRequestStatus: null,
        needsHumanReason: input.needsHumanReason,
    });
    if (input.needsHumanReason ===
        publisher_events_1.WORKFLOW_NEEDS_HUMAN_REASONS.assigneeResolution &&
        (input.assigneeResolution === "missing" ||
            input.assigneeResolution === "multiple")) {
        const next = (0, assignee_resolution_1.buildAssigneeResolutionNext)(input.responseLanguage, input.assigneeResolution);
        presentation.commentNext = next;
        presentation.cliNext = next;
    }
    return {
        issue: input.issue,
        previousSnapshot: input.previousSnapshot,
        nextSnapshot,
        handoffPullRequestSnapshot: null,
        runMode: input.runMode ?? types_3.WORKER_RUN_MODES.workflowExecute,
        requestedOutcome: constants_1.WORKER_OUTCOMES.waitHuman,
        finalOutcome: constants_1.WORKER_OUTCOMES.waitHuman,
        summary: input.summary,
        comment: null,
        facts: input.facts,
        branchName: input.branchName,
        baseBranch: input.baseBranch,
        pullRequestThreadId: input.pullRequestThreadId,
        pullRequestUrl: input.pullRequestUrl,
        scannedInputCursor: input.cursorMode === "explicit_only"
            ? (input.scannedInputCursor ?? null)
            : (input.scannedInputCursor ??
                input.workflowState?.lastScannedCommentCursor ??
                null),
        workflowTemplateName: input.workflowTemplateName,
        workflowState: input.workflowState === null
            ? null
            : {
                ...(0, ai_run_accounting_1.applyAiRunAccountingToWorkflowState)({
                    workflowState: input.workflowState,
                    ...(input.totalAiRunHours !== undefined
                        ? { totalAiRunHours: input.totalAiRunHours }
                        : {}),
                }),
                lastOutcome: constants_1.WORKER_OUTCOMES.waitHuman,
                needsHumanReason: input.needsHumanReason ?? null,
            },
        plannedIssueTitle: null,
        ...(input.invalidWorkflowStatePolicy !== undefined
            ? { invalidWorkflowStatePolicy: input.invalidWorkflowStatePolicy }
            : {}),
        planningIntent: null,
        sameIssueReplanSource: null,
        completedPendingReplan: false,
        continuation: null,
        needsHumanReason: input.needsHumanReason,
        responseLanguage: input.responseLanguage,
        result: null,
        presentation,
        incrementsConsecutiveAiRuns: true,
        recordsRunOutcome: true,
    };
}
function buildSuccessfulTransitionState(config, claimedIssue, workerExecution) {
    const effectiveConfig = resolveWorkerExecutionEffectiveConfig(config, workerExecution);
    const executedAt = new Date().toISOString();
    const { requestedOutcome, finalOutcome, summary, comment, needsHumanReason, handoffToPr: outcomeHandoffToPr, } = resolveSuccessfulTransitionOutcome(effectiveConfig, workerExecution);
    const { nextPendingPlanningIntent, pendingPlanning } = resolveSuccessfulPendingPlanning(workerExecution, needsHumanReason);
    let nextWorkflowState = buildNextSuccessfulWorkflowState({
        workerExecution,
        effectiveConfig,
        executedAt,
        finalOutcome,
        nextPendingPlanningIntent,
        pendingPlanning,
        needsHumanReason,
    });
    const terminalSuccess = (0, results_1.isTerminalWorkflowSuccessCandidate)({
        runMode: workerExecution.runMode,
        finalOutcome,
        recordsRunOutcome: workerExecution.recordsRunOutcome,
        continuation: workerExecution.continuation,
        workflowState: nextWorkflowState,
    });
    if (terminalSuccess) {
        nextWorkflowState = (0, followup_recommendation_state_1.applyWorkflowClosingFollowupRecommendation)({
            workflowState: nextWorkflowState,
            recommendation: workerExecution.followupRecommendation,
            recommendationSource: (0, followup_recommendation_state_1.buildWorkflowClosingFollowupRecommendationSource)({
                workerExecution,
            }),
        });
    }
    const issueCompletionTransition = resolveIssueCompletionTransition({
        terminalSuccess,
        issueCompletion: effectiveConfig.issueCompletion,
        outcomeHandoffToPr,
        finalOutcome,
        needsHumanReason,
        nextWorkflowState,
        workerExecution,
    });
    nextWorkflowState = issueCompletionTransition.nextWorkflowState;
    const { pauseForIssueReview, transitionFinalOutcome, transitionNeedsHumanReason, handoffToPr, } = issueCompletionTransition;
    const shouldOmitWorkflowLabels = terminalSuccess && !handoffToPr && !pauseForIssueReview;
    const nextLabelProjection = resolveSuccessfulNextLabelProjection({
        handoffToPr,
        finalOutcome: transitionFinalOutcome,
        nextWorkflowState,
        readySnapshot: claimedIssue.aiReadySnapshot,
    });
    const handoffPullRequest = resolveHandoffPullRequestTransition({
        handoffToPr,
        config: effectiveConfig,
        rules: nextLabelProjection.snapshot.rules,
        workerExecution,
    });
    const presentation = buildSuccessfulTransitionPresentation({
        effectiveConfig,
        workerExecution,
        transitionFinalOutcome,
        summary,
        comment,
        nextWorkflowState,
        handoffToPr,
        handoffPullRequestStatus: handoffPullRequest.snapshot?.status ?? null,
        issueCompletion: effectiveConfig.issueCompletion,
        transitionNeedsHumanReason,
        terminalSuccess,
        pauseForIssueReview,
    });
    return {
        issue: workerExecution.issue,
        previousSnapshot: claimedIssue.aiRunningSnapshot,
        nextSnapshot: nextLabelProjection.snapshot,
        handoffPullRequestSnapshot: handoffPullRequest.snapshot,
        ...(handoffToPr
            ? {
                handoffPullRequestNeedsHumanReason: handoffPullRequest.needsHumanReason,
            }
            : {}),
        labelProjection: {
            ...(shouldOmitWorkflowLabels ? { omitWorkflowLabels: true } : {}),
        },
        runMode: workerExecution.runMode,
        requestedOutcome,
        finalOutcome: transitionFinalOutcome,
        summary,
        comment,
        facts: workerExecution.facts,
        branchName: workerExecution.branchName,
        baseBranch: (0, issue_branch_target_1.resolveIssueRunBaseBranch)(workerExecution.workflowState),
        pullRequestThreadId: workerExecution.facts.pullRequestThreadId,
        pullRequestUrl: workerExecution.pullRequestUrl,
        scannedInputCursor: workerExecution.scannedInputCursor,
        workflowTemplateName: workerExecution.workflowTemplateName,
        workflowState: nextWorkflowState,
        plannedIssueTitle: workerExecution.plannedIssueTitle,
        planningIntent: workerExecution.planningIntent,
        sameIssueReplanSource: resolveSameIssueReplanSource({
            workerExecution,
            finalOutcome: transitionFinalOutcome,
            needsHumanReason: transitionNeedsHumanReason,
        }),
        completedPendingReplan: workerExecution.runMode === types_3.WORKER_RUN_MODES.workflowPlan &&
            workerExecution.startedWithPlanningIntent === "replan",
        continuation: workerExecution.continuation,
        needsHumanReason: transitionNeedsHumanReason,
        responseLanguage: workerExecution.responseLanguage,
        result: workerExecution.result,
        presentation,
        incrementsConsecutiveAiRuns: workerExecution.incrementsConsecutiveAiRuns,
        recordsRunOutcome: workerExecution.recordsRunOutcome,
    };
}
function resolveSuccessfulPendingPlanning(workerExecution, needsHumanReason) {
    const pendingPlanningIntent = shouldPreservePendingPlanningIntent(workerExecution, needsHumanReason);
    const nextPendingPlanningIntent = pendingPlanningIntent
        ? "replan"
        : undefined;
    return {
        nextPendingPlanningIntent,
        pendingPlanning: resolveNextPendingPlanningMetadata({
            pendingPlanningIntent: nextPendingPlanningIntent,
            workerExecution,
        }),
    };
}
function buildSuccessfulTransitionPresentation(input) {
    return (0, transition_presentation_1.buildTransitionPresentation)({
        config: input.effectiveConfig,
        issue: input.workerExecution.issue,
        finalOutcome: input.transitionFinalOutcome,
        facts: input.workerExecution.facts,
        summary: input.summary,
        comment: input.comment,
        result: input.workerExecution.result,
        consecutiveAiRuns: input.workerExecution.consecutiveAiRuns,
        responseLanguage: input.workerExecution.responseLanguage,
        workflowState: input.nextWorkflowState,
        handoffToPr: input.handoffToPr,
        handoffPullRequestStatus: input.handoffPullRequestStatus,
        ...(input.handoffToPr
            ? { handoffIssueCompletion: input.issueCompletion }
            : {}),
        needsHumanReason: input.transitionNeedsHumanReason,
        terminalSuccess: input.terminalSuccess && !input.pauseForIssueReview,
    });
}
function resolveIssueCompletionTransition(input) {
    const issueReviewReadyWouldHandoffToPr = input.finalOutcome === constants_1.WORKER_OUTCOMES.waitHuman &&
        input.needsHumanReason === publisher_events_1.WORKFLOW_NEEDS_HUMAN_REASONS.reviewReady;
    const issueCompletionWouldHandoffToPr = (input.terminalSuccess || issueReviewReadyWouldHandoffToPr) &&
        shouldHandoffCompletedWorkflowToPullRequest({
            issue: input.workerExecution.issue,
            facts: input.workerExecution.facts,
        });
    const pauseForIssueReview = issueCompletionWouldHandoffToPr &&
        input.issueCompletion.target === "pause_on_issue";
    const nextWorkflowState = pauseForIssueReview && input.nextWorkflowState !== null
        ? {
            ...input.nextWorkflowState,
            lastOutcome: constants_1.WORKER_OUTCOMES.waitHuman,
            needsHumanReason: publisher_events_1.WORKFLOW_NEEDS_HUMAN_REASONS.reviewReady,
        }
        : input.nextWorkflowState;
    return {
        pauseForIssueReview,
        transitionFinalOutcome: pauseForIssueReview
            ? constants_1.WORKER_OUTCOMES.waitHuman
            : input.finalOutcome,
        transitionNeedsHumanReason: pauseForIssueReview
            ? publisher_events_1.WORKFLOW_NEEDS_HUMAN_REASONS.reviewReady
            : input.needsHumanReason,
        handoffToPr: !pauseForIssueReview &&
            (input.outcomeHandoffToPr || issueCompletionWouldHandoffToPr),
        nextWorkflowState,
    };
}
function buildNextSuccessfulWorkflowState(input) {
    if (input.workerExecution.workflowState === null) {
        return null;
    }
    const nextWorkflowState = {
        ...(0, execution_ownership_1.stripExecutionOwnership)((0, needs_human_1.applyWorkflowExecutionMetadata)(input.workerExecution.workflowState, {
            executedAt: input.executedAt,
            finalOutcome: input.finalOutcome,
            recordsRunOutcome: input.workerExecution.recordsRunOutcome,
            shouldClearPendingPlanningIntent: input.workerExecution.startedWithPlanningIntent !== null,
            pendingPlanningIntent: input.nextPendingPlanningIntent,
            pendingPlanningReason: input.pendingPlanning.reason,
            pendingPlanningSource: input.pendingPlanning.source,
            displayTimeZone: input.effectiveConfig.i18n.displayTimeZone,
        })),
        totalAiRunHours: (0, ai_run_accounting_1.resolveWorkerExecutionTotalAiRunHours)(input.workerExecution),
        needsHumanReason: input.needsHumanReason ?? null,
    };
    if (shouldClearResolvedWorkflowStartApproval(input)) {
        delete nextWorkflowState.pendingWorkflowStartApprovalIntent;
    }
    return nextWorkflowState;
}
function shouldClearResolvedWorkflowStartApproval(input) {
    return (input.workerExecution.runMode === types_3.WORKER_RUN_MODES.workflowPlan &&
        (input.finalOutcome === constants_1.WORKER_OUTCOMES.proceed ||
            input.workerExecution.workflowStartApproval?.required === false));
}
function resolveWorkerExecutionEffectiveConfig(config, workerExecution) {
    return (0, control_plane_config_1.resolveIssueEffectiveConfigForWorkflowState)(config, workerExecution.workflowState);
}
function shouldPreservePendingPlanningIntent(workerExecution, needsHumanReason) {
    return (((workerExecution.runMode === types_3.WORKER_RUN_MODES.workflowExecute ||
        workerExecution.runMode === types_3.WORKER_RUN_MODES.workflowClosing) &&
        workerExecution.continuation?.strategy === "replan_same_issue") ||
        (workerExecution.runMode === types_3.WORKER_RUN_MODES.workflowPlan &&
            workerExecution.startedWithPlanningIntent === "replan" &&
            needsHumanReason === publisher_events_1.WORKFLOW_NEEDS_HUMAN_REASONS.runLimit));
}
function resolveNextPendingPlanningMetadata(input) {
    if (input.pendingPlanningIntent !== "replan") {
        return { reason: null, source: undefined };
    }
    return {
        reason: input.workerExecution.continuation?.reason ??
            input.workerExecution.workflowState?.pendingPlanningReason ??
            null,
        source: input.workerExecution.workflowState?.pendingPlanningSource,
    };
}
function resolveSameIssueReplanSource(input) {
    if (input.needsHumanReason === publisher_events_1.WORKFLOW_NEEDS_HUMAN_REASONS.runLimit &&
        (input.workerExecution.continuation?.strategy === "replan_same_issue" ||
            (input.workerExecution.runMode === types_3.WORKER_RUN_MODES.workflowPlan &&
                input.workerExecution.startedWithPlanningIntent === "replan"))) {
        return "run_limit_downgrade";
    }
    if (input.workerExecution.runMode === types_3.WORKER_RUN_MODES.workflowPlan &&
        input.workerExecution.startedWithPlanningIntent === "replan" &&
        input.finalOutcome === constants_1.WORKER_OUTCOMES.proceed) {
        return "replan_completion";
    }
    if (input.workerExecution.continuation?.strategy !== "replan_same_issue" ||
        input.finalOutcome !== constants_1.WORKER_OUTCOMES.proceed) {
        return null;
    }
    return "worker_replan_same_issue";
}
function resolveSuccessfulTransitionOutcome(config, workerExecution) {
    const requestedOutcome = workerExecution.workerOutcome;
    const comment = workerExecution.result.humanComment;
    const baseSummary = workerExecution.runMode === types_3.WORKER_RUN_MODES.workflowExecute &&
        !workerExecution.recordsRunOutcome &&
        workerExecution.continuation?.strategy !== "replan_same_issue" &&
        requestedOutcome === constants_1.WORKER_OUTCOMES.proceed &&
        workerExecution.workflowState !== null
        ? (0, presentation_1.buildWorkflowStepSummary)(workerExecution.workflowState, workerExecution.responseLanguage)
        : workerExecution.result.resultSummary;
    const shouldApplyAiRunLimit = workerExecution.incrementsConsecutiveAiRuns &&
        !(0, recurring_1.isRecurringParentWorkflowState)(workerExecution.workflowState) &&
        !(0, results_1.isTerminalWorkflowSuccessCandidate)({
            runMode: workerExecution.runMode,
            finalOutcome: requestedOutcome,
            recordsRunOutcome: workerExecution.recordsRunOutcome,
            continuation: workerExecution.continuation,
            workflowState: workerExecution.workflowState,
        }) &&
        (workerExecution.runMode === types_3.WORKER_RUN_MODES.workflowPlan ||
            workerExecution.runMode === types_3.WORKER_RUN_MODES.workflowClosing ||
            (0, run_state_helpers_1.isImplicitWorkflowRun)(workerExecution.runMode, workerExecution.workflowState));
    const totalAiRunHours = (0, ai_run_accounting_1.resolveWorkerExecutionTotalAiRunHours)(workerExecution);
    const runLimit = (0, run_limit_policy_1.resolveAiRunLimitPolicy)({
        config,
        consecutiveAiRuns: workerExecution.consecutiveAiRuns,
        totalAiRunHours,
    });
    const finalOutcome = shouldApplyAiRunLimit &&
        requestedOutcome === constants_1.WORKER_OUTCOMES.proceed &&
        runLimit.reached
        ? constants_1.WORKER_OUTCOMES.waitHuman
        : requestedOutcome;
    const summary = shouldApplyAiRunLimit &&
        requestedOutcome === constants_1.WORKER_OUTCOMES.proceed &&
        finalOutcome === constants_1.WORKER_OUTCOMES.waitHuman
        ? (0, presentation_1.appendAiRunLimitHandoffSummary)(workerExecution.responseLanguage, baseSummary, {
            reachedKind: runLimit.reachedKind,
            consecutiveAiRuns: workerExecution.consecutiveAiRuns,
            totalAiRunHours,
            maxRuns: config.aiRunLimits.maxRuns,
            maxHours: config.aiRunLimits.maxHours,
        })
        : baseSummary;
    const needsHumanReason = shouldApplyAiRunLimit &&
        requestedOutcome === constants_1.WORKER_OUTCOMES.proceed &&
        finalOutcome === constants_1.WORKER_OUTCOMES.waitHuman
        ? "run_limit"
        : finalOutcome === constants_1.WORKER_OUTCOMES.waitHuman
            ? workerExecution.needsHumanReason
            : null;
    return {
        requestedOutcome,
        finalOutcome,
        summary,
        comment,
        needsHumanReason,
        handoffToPr: false,
    };
}
function shouldHandoffCompletedWorkflowToPullRequest(input) {
    return (input.issue.kind === types_1.TRACKER_ITEM_KINDS.issue &&
        (input.facts.openPullRequestExists ||
            input.facts.pullRequestThreadId !== null ||
            input.facts.branchAheadOfBase));
}
function resolveSuccessfulNextLabelProjection(input) {
    const baseNextSnapshot = {
        status: input.handoffToPr
            ? types_2.WORKFLOW_STATUSES.aiWorkingInPr
            : input.finalOutcome === constants_1.WORKER_OUTCOMES.proceed &&
                input.nextWorkflowState !== null
                ? types_2.WORKFLOW_STATUSES.aiRunning
                : (0, results_1.outcomeToStatus)(input.finalOutcome),
        rules: [...input.readySnapshot.rules],
    };
    return (0, recurring_1.resolveRecurringProjection)({
        snapshot: baseNextSnapshot,
        workflowState: input.nextWorkflowState,
    });
}
function resolveHandoffPullRequestTransition(input) {
    if (!input.handoffToPr) {
        return { snapshot: null, needsHumanReason: null };
    }
    const runLimitReached = input.workerExecution.incrementsConsecutiveAiRuns &&
        !(0, recurring_1.isRecurringParentWorkflowState)(input.workerExecution.workflowState) &&
        (0, run_limit_policy_1.resolveAiRunLimitPolicy)({
            config: input.config,
            consecutiveAiRuns: input.workerExecution.consecutiveAiRuns,
            totalAiRunHours: (0, ai_run_accounting_1.resolveWorkerExecutionTotalAiRunHours)(input.workerExecution),
        }).reached;
    const snapshot = buildHandoffPullRequestSnapshot(input.config, input.rules, runLimitReached);
    return {
        snapshot,
        needsHumanReason: snapshot.status === types_2.WORKFLOW_STATUSES.aiNeedsHuman
            ? runLimitReached
                ? publisher_events_1.WORKFLOW_NEEDS_HUMAN_REASONS.runLimit
                : publisher_events_1.WORKFLOW_NEEDS_HUMAN_REASONS.reviewReady
            : null,
    };
}
function buildHandoffPullRequestSnapshot(config, rules, runLimitReached = false) {
    const shouldQueuePullRequestAutomation = (0, issue_completion_1.shouldAlwaysRunPullRequestReview)(config.issueCompletion) ||
        (0, issue_completion_1.shouldEvaluatePullRequestReviewNecessity)(config.issueCompletion) ||
        (0, issue_completion_1.isPullRequestAutoMergePolicyEnabled)(config.issueCompletion);
    const shouldPauseOnPullRequest = (0, issue_completion_1.shouldSkipPullRequestReview)(config.issueCompletion) &&
        !shouldQueuePullRequestAutomation;
    return {
        status: runLimitReached || shouldPauseOnPullRequest
            ? types_2.WORKFLOW_STATUSES.aiNeedsHuman
            : types_2.WORKFLOW_STATUSES.aiReady,
        rules: [...rules],
    };
}
function createFailureSeed(config, issue, consecutiveAiRuns, totalAiRunHours, runMode = null, workflowTemplateName = null, workflowState = null) {
    return {
        issue,
        branchName: issue.sourceBranchName ??
            (0, default_issue_workspace_manager_1.resolveIssueBranchName)(config.branchPrefix, issue),
        pullRequestUrl: null,
        commentUrl: null,
        consecutiveAiRuns,
        totalAiRunHours,
        runMode,
        workflowTemplateName,
        workflowState,
        needsHumanReason: null,
    };
}
