"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.loadPersistedWorkflowStatesForIssues = void 0;
exports.isServiceRunnableAssignment = isServiceRunnableAssignment;
exports.hasServiceRunnableBasePreconditions = hasServiceRunnableBasePreconditions;
exports.isServiceWorkerRunnableCandidate = isServiceWorkerRunnableCandidate;
exports.hasHumanResumeWorkerAction = hasHumanResumeWorkerAction;
exports.isServiceControlPlaneActionCandidate = isServiceControlPlaneActionCandidate;
exports.shouldSkipForServiceRuleLabels = shouldSkipForServiceRuleLabels;
exports.hasPendingWorkflowCommandForScheduling = hasPendingWorkflowCommandForScheduling;
exports.isReadyRunnableCandidate = isReadyRunnableCandidate;
exports.isRecurringParentRunnableCandidate = isRecurringParentRunnableCandidate;
exports.isScheduledRunRunnableCandidate = isScheduledRunRunnableCandidate;
exports.isNeedsHumanRunnableCandidate = isNeedsHumanRunnableCandidate;
exports.loadPendingWorkflowCommandStateForScheduling = loadPendingWorkflowCommandStateForScheduling;
exports.loadCandidateBlockingState = loadCandidateBlockingState;
exports.loadUnblockedSchedulingCandidates = loadUnblockedSchedulingCandidates;
const canonical_workflow_state_1 = require("../../comments/canonical-workflow-state");
const managed_comments_1 = require("../../comments/managed-comments");
const types_1 = require("../../platform/ticket-tracker/types");
const types_2 = require("../../platform/workflow-state/types");
const execution_ownership_1 = require("../../run/execution-ownership");
const controller_child_reflection_1 = require("../../run/run-once-cycle/controller-child-reflection");
const dependencies_1 = require("../../run/run-once-cycle/dependencies");
const preflight_resolution_blockers_1 = require("../../run/run-once-cycle/preflight-resolution-blockers");
const shared_1 = require("../../run/run-once-cycle/shared");
const plan_progress_1 = require("../../workflows/plan-progress");
const recurring_1 = require("../../workflows/recurring");
const recurring_auto_stop_1 = require("../../workflows/recurring-auto-stop");
const scheduled_run_1 = require("../../workflows/scheduled-run");
const persisted_state_1 = require("../../workflows/state/persisted-state");
var workflow_state_read_support_1 = require("../../workflows/workflow-state-read-support");
Object.defineProperty(exports, "loadPersistedWorkflowStatesForIssues", { enumerable: true, get: function () { return workflow_state_read_support_1.loadPersistedWorkflowStatesForIssues; } });
const workflow_timeline_scan_1 = require("../../workflows/workflow-timeline-scan");
function isServiceRunnableAssignment(input) {
    if (!Array.isArray(input.assignees)) {
        return false;
    }
    if (!input.currentUserLogin || input.assignees.length !== 1) {
        return false;
    }
    return input.assignees[0] === input.currentUserLogin;
}
function hasServiceRunnableBasePreconditions(input) {
    return (isServiceRunnableAssignment({
        assignees: input.assignees,
        ...(input.currentUserLogin !== undefined
            ? { currentUserLogin: input.currentUserLogin }
            : {}),
    }) && !shouldSkipForServiceRuleLabels(input.rules));
}
function isServiceWorkerRunnableCandidate(input) {
    return (hasServiceRunnableBasePreconditions({
        assignees: input.issue.assignees,
        rules: input.issue.workflowState.rules,
        ...(input.currentUserLogin !== undefined
            ? { currentUserLogin: input.currentUserLogin }
            : {}),
    }) &&
        !(0, recurring_1.isRecurringParentWorkflowState)(input.workflowState) &&
        !(0, scheduled_run_1.hasActiveScheduledRun)(input.workflowState) &&
        (input.workflowState?.pendingPlanningIntent !== undefined ||
            !(0, plan_progress_1.hasControllerChildIssueControlPlaneAction)(input.workflowState)) &&
        ((0, plan_progress_1.hasWorkflowWorkerExecutableAction)(input.workflowState) ||
            hasHumanResumeWorkerAction(input)));
}
function hasHumanResumeWorkerAction(input) {
    return ((0, persisted_state_1.isHumanInputResumeProjection)({
        snapshot: input.issue.workflowState,
        workflowState: input.workflowState,
    }) && (0, plan_progress_1.hasWorkflowHumanResumeExecutableAction)(input.workflowState));
}
function isServiceControlPlaneActionCandidate(input) {
    return (hasServiceRunnableBasePreconditions({
        assignees: input.issue.assignees,
        rules: input.issue.workflowState.rules,
        ...(input.currentUserLogin !== undefined
            ? { currentUserLogin: input.currentUserLogin }
            : {}),
    }) &&
        !(0, recurring_1.isRecurringParentWorkflowState)(input.workflowState) &&
        !(0, scheduled_run_1.hasActiveScheduledRun)(input.workflowState) &&
        input.workflowState?.pendingPlanningIntent === undefined &&
        (0, plan_progress_1.hasControllerChildIssueControlPlaneAction)(input.workflowState));
}
function shouldSkipForServiceRuleLabels(rules) {
    return rules.includes(types_2.WORKFLOW_RULES.aiDisabled);
}
function hasPendingWorkflowCommandForScheduling(input) {
    const workflowState = input.workflowState ?? null;
    const scan = (0, workflow_timeline_scan_1.scanWorkflowTimeline)({
        comments: input.comments,
        issueBody: input.issue.kind === types_1.TRACKER_ITEM_KINDS.issue ? input.issue.body : null,
        workflowState,
    });
    if (scan.commandEvents.length === 0) {
        return false;
    }
    if (scan.workflowCommandEvents.length > 0) {
        return true;
    }
    if (workflowState !== null) {
        return true;
    }
    return !hasDedupedFeedbackForLatestCommand({
        comments: input.comments,
        scan,
    });
}
function hasDedupedFeedbackForLatestCommand(input) {
    const latestCommand = input.scan.commandEvents[input.scan.commandEvents.length - 1];
    if (latestCommand === undefined || !("comment" in latestCommand)) {
        return false;
    }
    const commentsAfterCommand = (0, workflow_timeline_scan_1.sliceCommentsAfterCursor)((0, workflow_timeline_scan_1.sortTimelineComments)(input.comments), (0, workflow_timeline_scan_1.toWorkflowCommentCursor)(latestCommand.comment));
    for (const comment of commentsAfterCommand) {
        if ((0, workflow_timeline_scan_1.classifyWorkflowTimelineComment)(comment) !== "managed") {
            break;
        }
        if ((0, managed_comments_1.isManagedCommandFeedbackComment)(comment.body)) {
            return true;
        }
    }
    return false;
}
function isReadyRunnableCandidate(input) {
    return (hasServiceRunnableBasePreconditions({
        assignees: input.issue.assignees,
        rules: input.issue.workflowState.rules,
        ...(input.currentUserLogin !== undefined
            ? { currentUserLogin: input.currentUserLogin }
            : {}),
    }) &&
        !(0, recurring_1.isRecurringParentWorkflowState)(input.workflowState) &&
        !(0, scheduled_run_1.hasActiveScheduledRun)(input.workflowState));
}
function isRecurringParentRunnableCandidate(input) {
    return (isServiceRunnableAssignment({
        assignees: input.issue.assignees,
        ...(input.currentUserLogin !== undefined
            ? { currentUserLogin: input.currentUserLogin }
            : {}),
    }) &&
        input.workflowState !== null &&
        (0, recurring_1.isRecurringParentWorkflowState)(input.workflowState) &&
        !(0, execution_ownership_1.isExecutionOwnershipActive)(input.workflowState.executionOwnership) &&
        (0, recurring_auto_stop_1.isRecurringLifecycleTaskDue)(input.workflowState));
}
function isScheduledRunRunnableCandidate(input) {
    return (isServiceRunnableAssignment({
        assignees: input.issue.assignees,
        ...(input.currentUserLogin !== undefined
            ? { currentUserLogin: input.currentUserLogin }
            : {}),
    }) &&
        input.workflowState !== null &&
        (0, scheduled_run_1.hasActiveScheduledRun)(input.workflowState) &&
        !(0, execution_ownership_1.isExecutionOwnershipActive)(input.workflowState.executionOwnership) &&
        (0, scheduled_run_1.isScheduledRunDue)(input.workflowState));
}
function isNeedsHumanRunnableCandidate(input) {
    return (input.issue.kind === types_1.TRACKER_ITEM_KINDS.pullRequest &&
        hasServiceRunnableBasePreconditions({
            assignees: input.issue.assignees,
            rules: input.issue.workflowState.rules,
            ...(input.currentUserLogin !== undefined
                ? { currentUserLogin: input.currentUserLogin }
                : {}),
        }));
}
async function loadPendingWorkflowCommandStateForScheduling(ticketTracker, issues, issueCommentsById) {
    const pendingCommandStates = await Promise.all(issues.map(async (issue) => {
        const comments = issueCommentsById?.get(issue.id) ??
            (await (0, shared_1.loadSortedIssueComments)(ticketTracker, issue.id, {
                timeline: "issue-only",
            }));
        const canonical = (0, canonical_workflow_state_1.resolveCanonicalWorkflowStateComment)(comments, "en");
        return {
            issueId: issue.id,
            hasPendingWorkflowCommand: hasPendingWorkflowCommandForScheduling({
                issue,
                comments,
                workflowState: canonical.kind === "found" ? canonical.workflowState : null,
            }),
        };
    }));
    return new Map(pendingCommandStates.map(({ issueId, hasPendingWorkflowCommand }) => [
        issueId,
        hasPendingWorkflowCommand,
    ]));
}
async function loadCandidateBlockingState(input) {
    return Promise.all(input.issues.map(async (issue) => ({
        issue,
        workflowState: input.workflowStateByIssueId.get(issue.id) ?? null,
        blockers: await input.ticketTracker.listBlockingDependencies(issue.id),
    })));
}
async function loadUnblockedSchedulingCandidates(input) {
    const candidates = await Promise.all((await loadCandidateBlockingState({
        ticketTracker: input.ticketTracker,
        issues: input.issues,
        workflowStateByIssueId: input.workflowStateByIssueId,
    })).map(async ({ issue, blockers, workflowState }) => {
        const openExecutionBlockers = (0, dependencies_1.resolveOpenExecutionBlockingDependencies)({
            strategy: input.config.dependencies.strategy,
            workflowState,
            blockers,
            parentIssueDisplayId: issue.displayId,
        });
        const hasReflectableCompletedChild = (0, plan_progress_1.hasControllerChildIssueControlPlaneAction)(workflowState) &&
            (await (0, controller_child_reflection_1.hasReflectableCompletedControllerChild)({
                ticketTracker: input.ticketTracker,
                parentIssue: issue,
                workflowState,
                blockers,
            }));
        const hasPendingPlanning = workflowState?.pendingPlanningIntent !== undefined;
        const canBypassOpenBlockersForPendingPlanning = await (0, preflight_resolution_blockers_1.canPendingPlanningBypassOpenExecutionBlockers)({
            parentIssueId: issue.id,
            hasPendingPlanning,
            openExecutionBlockers,
            ticketTracker: input.ticketTracker,
        });
        const openBlockersAllowControllerReflection = openExecutionBlockers.length > 0 &&
            (0, controller_child_reflection_1.areOpenBlockersOnlyUnresolvedMaterializedControllerChildren)({
                workflowState,
                blockers: openExecutionBlockers,
            }) &&
            hasReflectableCompletedChild;
        return {
            issue,
            workflowState,
            hasReflectableCompletedControllerChild: hasReflectableCompletedChild,
            isUnblocked: canBypassOpenBlockersForPendingPlanning ||
                openExecutionBlockers.length === 0 ||
                openBlockersAllowControllerReflection,
        };
    }));
    return candidates
        .filter((candidate) => candidate.isUnblocked)
        .map(({ issue, workflowState, hasReflectableCompletedControllerChild }) => ({
        issue,
        workflowState,
        hasReflectableCompletedControllerChild,
    }));
}
