"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.runWorkflowSetupPhase = runWorkflowSetupPhase;
const setup_pipeline_1 = require("../../workflows/setup-pipeline");
const config_decision_approval_support_1 = require("../../commands/service-runtime/config-decision-approval-support");
const config_explicit_command_support_1 = require("../../commands/service-runtime/config-explicit-command-support");
const config_plan_support_1 = require("../../commands/service-runtime/config-plan-support");
const config_publish_spec_support_1 = require("../../commands/service-runtime/config-publish-spec-support");
const config_publish_execution_1 = require("../../commands/service-runtime/config-publish-execution");
const config_scan_1 = require("../../commands/service-runtime/config-scan");
const config_scan_helpers_1 = require("../../commands/service-runtime/config-scan-helpers");
const catalog_1 = require("../../i18n/catalog");
const types_1 = require("../../platform/workflow-state/types");
const plan_progress_1 = require("../../workflows/plan-progress");
const publisher_1 = require("../../workflows/publisher");
const publisher_events_1 = require("../../workflows/publisher-events");
const recurring_1 = require("../../workflows/recurring");
const scheduled_run_1 = require("../../workflows/scheduled-run");
const visible_update_builders_1 = require("../../workflows/visible-update-builders");
const workflow_projection_support_1 = require("../../workflows/workflow-projection-support");
const execution_ownership_1 = require("../execution-ownership");
const constants_1 = require("../constants");
const freshness_1 = require("./freshness");
const presentation_1 = require("./presentation");
const publisher_factory_1 = require("./publisher-factory");
const results_1 = require("./results");
const shared_1 = require("./shared");
const workflow_template_root_1 = require("./workflow-template-root");
async function runWorkflowSetupPhase(context, issues) {
    const remainingIssues = [];
    const summaries = [];
    for (const issue of issues) {
        const result = await processWorkflowSetupIssue(context, issue);
        if (result.kind === "not_setup") {
            remainingIssues.push(issue);
            continue;
        }
        if (result.summary !== null) {
            summaries.push(result.summary);
        }
        if (result.continueIssue !== undefined) {
            remainingIssues.push(result.continueIssue);
        }
    }
    return {
        issues: remainingIssues,
        summaries,
    };
}
async function processWorkflowSetupIssue(context, issue) {
    if (!(0, config_scan_helpers_1.isPotentialWorkflowSetupIssueCandidate)(issue)) {
        return { kind: "not_setup" };
    }
    const latestIssue = await context.freshTicketTracker.getIssue(issue.id);
    if (!(0, config_scan_helpers_1.isPotentialWorkflowSetupIssueCandidate)(latestIssue)) {
        return { kind: "not_setup" };
    }
    const scanState = await (0, config_scan_helpers_1.resolveWorkflowScanState)({
        ticketTracker: context.freshTicketTracker,
        issue: latestIssue,
        responseLanguage: context.config.i18n.defaultLanguage,
    });
    const source = await resolveRunnableWorkflowSetupSource({
        context,
        issue: latestIssue,
        scanState,
    });
    if (source === null) {
        return { kind: "not_setup" };
    }
    const responseLanguage = context.config.i18n.defaultLanguage;
    const acceptedAt = resolveWorkflowSetupAcceptedAt(source, latestIssue);
    const { logger } = (0, shared_1.buildIssueLogContext)(context.config, latestIssue, context.logHomeDirectory);
    await appendWorkflowSetupRunStart({
        logger,
        issue: latestIssue,
        source,
        acceptedAt,
        workerId: context.workerIdentity.workerId,
    });
    let setupResult;
    try {
        setupResult = await (0, setup_pipeline_1.runWorkflowSetupPipeline)({
            repoRoot: (0, workflow_template_root_1.getWorkflowTemplateRepoRoot)(context),
            workspacePath: context.cwd,
            config: context.config,
            worker: context.worker,
            title: latestIssue.title,
            issueBody: latestIssue.body,
            comments: scanState.comments,
            issue: latestIssue,
            sourceKind: source.kind,
            sourceText: source.text,
            acceptedAt,
            displayTimeZone: context.config.i18n.displayTimeZone,
            responseLanguage,
            bootstrapWorkflowState: scanState.stickyState,
            workflowSurface: scanState.stickyState?.workflowSurface ?? "issue",
        });
    }
    catch (error) {
        if (isWorkflowSetupAutofillCapabilityMissing(error)) {
            return { kind: "not_setup" };
        }
        await logger.appendSection("AI workflow setup failure", (0, results_1.renderFailureDetails)(error, responseLanguage));
        return {
            kind: "handled",
            summary: buildWorkflowSetupFailedSummary({
                issue: latestIssue,
                responseLanguage,
                error,
            }),
        };
    }
    if (setupResult.kind === "deferred") {
        await logger.appendSection("AI workflow setup deferred", [
            `reason: ${setupResult.reason}`,
            `attempted worker execution: ${setupResult.attemptedWorkerExecution}`,
            `cooldown until: ${setupResult.cooldownUntil ?? "(none)"}`,
        ].join("\n"));
        return {
            kind: "handled",
            summary: buildWorkflowSetupDeferredSummary({
                issue: latestIssue,
                responseLanguage,
                setupResult,
            }),
        };
    }
    if (setupResult.kind === "handoff") {
        return publishWorkflowSetupHandoff({
            context,
            issue: latestIssue,
            scanState,
            source,
            responseLanguage,
            setupResult,
            logger,
        });
    }
    await logger.appendSection("AI workflow setup workflow options", formatJsonForIssueLog(setupResult.workflowOptions));
    if (setupResult.kind !== "updated") {
        if (source.kind === "fresh_comment") {
            return publishFreshCommentFallbackConfigScan({
                context,
                issue: latestIssue,
                responseLanguage,
            });
        }
        return { kind: "not_setup" };
    }
    const planSpec = await buildWorkflowSetupPlanSpec({
        context,
        issue: latestIssue,
        scanState,
        source,
        acceptedAt,
        workflowCommand: {
            kind: "update",
            bodyAfterCommand: "",
            ...setupResult.workflowOptions,
        },
    });
    return publishWorkflowSetupPlanSpec({
        context,
        issue: latestIssue,
        scanState,
        responseLanguage,
        planSpec,
        source,
        summary: (0, catalog_1.translate)(responseLanguage, "aiWorkflowOptionAutofill.summary"),
    });
}
async function publishWorkflowSetupHandoff(input) {
    await input.logger.appendSection("AI workflow setup handoff", input.setupResult.summary);
    const planSpec = buildWorkflowSetupHandoffPlanSpec(input);
    return publishWorkflowSetupPlanSpec({
        context: input.context,
        issue: input.issue,
        scanState: input.scanState,
        responseLanguage: input.responseLanguage,
        planSpec,
        source: input.source,
        summary: input.setupResult.summary,
        outcome: constants_1.RUN_ISSUE_OUTCOMES.queuedHuman,
        nextStep: (0, catalog_1.translate)(input.responseLanguage, "run.presentation.failNext"),
    });
}
async function publishFreshCommentFallbackConfigScan(input) {
    const plan = await (0, config_scan_1.scanIssueWorkflowConfiguration)({
        repoRoot: (0, workflow_template_root_1.getWorkflowTemplateRepoRoot)(input.context),
        config: input.context.config,
        ticketTracker: input.context.freshTicketTracker,
        issue: input.issue,
        enableImplicitReplan: true,
    });
    const publishResult = await publishWorkflowSetupConfigScanPlan({
        context: input.context,
        issue: input.issue,
        plan,
        outcome: constants_1.RUN_ISSUE_OUTCOMES.queuedAi,
    });
    if (publishResult === null) {
        return { kind: "not_setup" };
    }
    return {
        kind: "handled",
        ...(publishResult.continueIssue !== undefined
            ? { continueIssue: publishResult.continueIssue }
            : {}),
        summary: (0, results_1.buildRunCliSummary)({
            issue: input.issue,
            outcome: constants_1.RUN_ISSUE_OUTCOMES.queuedAi,
            responseLanguage: input.responseLanguage,
            summary: (0, catalog_1.translate)(input.responseLanguage, "workflowSetup.commandlessFallback.summary"),
            commentUrl: (0, publisher_factory_1.resolveRunWorkflowPublicationCommentUrl)(publishResult.publication),
            prUrl: null,
            nextStep: (0, catalog_1.translate)(input.responseLanguage, "run.presentation.proceedNext"),
        }),
    };
}
async function publishWorkflowSetupPlanSpec(input) {
    if (isNonMutatingWorkflowSetupPlan(input.planSpec, input.scanState.stickyState)) {
        return input.source.kind === "tracker_issue_body"
            ? { kind: "not_setup" }
            : { kind: "handled", summary: null };
    }
    const plan = (0, config_plan_support_1.materializeServiceRuntimeConfigScanPlan)({
        planSpec: input.planSpec,
        issueComments: input.scanState.comments,
        workflowLabels: input.context.config.ticketTracker.workflowLabels,
    });
    const publishResult = await publishWorkflowSetupConfigScanPlan({
        context: input.context,
        issue: input.issue,
        plan,
        outcome: input.outcome ?? constants_1.RUN_ISSUE_OUTCOMES.queuedAi,
    });
    if (publishResult === null) {
        return { kind: "handled", summary: null };
    }
    return {
        kind: "handled",
        ...(publishResult.continueIssue !== undefined
            ? { continueIssue: publishResult.continueIssue }
            : {}),
        summary: (0, results_1.buildRunCliSummary)({
            issue: input.issue,
            outcome: input.outcome ?? constants_1.RUN_ISSUE_OUTCOMES.queuedAi,
            responseLanguage: input.responseLanguage,
            summary: input.summary,
            commentUrl: (0, publisher_factory_1.resolveRunWorkflowPublicationCommentUrl)(publishResult.publication),
            prUrl: null,
            nextStep: input.nextStep ??
                (0, catalog_1.translate)(input.responseLanguage, "run.presentation.proceedNext"),
        }),
    };
}
async function publishWorkflowSetupConfigScanPlan(input) {
    const publication = await (0, config_publish_execution_1.publishServiceRuntimeConfigScanPlan)({
        repoRoot: (0, workflow_template_root_1.getWorkflowTemplateRepoRoot)(input.context),
        ticketTrackerKind: input.context.config.ticketTracker.kind,
        displayTimeZone: input.context.config.i18n.displayTimeZone,
        workflowLabels: input.context.config.ticketTracker.workflowLabels,
        ticketTracker: input.context.freshTicketTracker,
        plan: input.plan,
        eventHooks: buildWorkflowSetupEventHooks(input.context),
    });
    if (publication === null) {
        return null;
    }
    input.context.ticketTracker.resetVolatileIssueReads(input.issue.id);
    const continueIssue = resolveWorkflowSetupContinuationIssue({
        issue: input.issue,
        publication,
        outcome: input.outcome,
    });
    return {
        publication,
        ...(continueIssue !== undefined ? { continueIssue } : {}),
    };
}
function resolveWorkflowSetupContinuationIssue(input) {
    if (input.outcome !== constants_1.RUN_ISSUE_OUTCOMES.queuedAi) {
        return undefined;
    }
    const issue = buildWorkflowSetupContinuationIssue({
        issue: input.issue,
        publication: input.publication,
    });
    if (input.publication.publishStatus !== "applied" ||
        input.publication.targetClosed ||
        !(0, types_1.isRunnableWorkflowState)(issue.workflowState)) {
        return undefined;
    }
    if (!isImmediateWorkflowPlanSetupState(input.publication.targetWorkflowState)) {
        return undefined;
    }
    return issue;
}
function buildWorkflowSetupContinuationIssue(input) {
    const targetWorkflowProjection = input.publication.targetWorkflowProjection;
    return {
        ...input.issue,
        ...input.publication.targetIssue,
        workflowState: targetWorkflowProjection !== null
            ? {
                status: targetWorkflowProjection.status,
                rules: [...targetWorkflowProjection.rules],
            }
            : input.issue.workflowState,
        ...(input.publication.targetClosed ? { isOpen: false } : {}),
    };
}
function isImmediateWorkflowPlanSetupState(workflowState) {
    return (workflowState !== null &&
        !(0, execution_ownership_1.isExecutionOwnershipActive)(workflowState.executionOwnership) &&
        !(0, scheduled_run_1.hasActiveScheduledRun)(workflowState) &&
        !(0, recurring_1.isRecurringParentWorkflowState)(workflowState) &&
        !(0, plan_progress_1.hasControllerChildIssueControlPlaneAction)(workflowState) &&
        (workflowState.plan === null ||
            workflowState.pendingPlanningIntent !== undefined));
}
function buildWorkflowSetupEventHooks(context) {
    return {
        config: context.config,
        worker: context.worker,
        ...(context.logHomeDirectory !== undefined
            ? { homeDirectory: context.logHomeDirectory }
            : {}),
    };
}
async function appendWorkflowSetupRunStart(input) {
    await input.logger.appendRunStart({
        runKind: "ai workflow setup",
        issue: input.issue,
        currentLabels: input.issue.labelNames ?? [],
        pullRequestUrl: null,
        workerId: input.workerId,
    });
    await input.logger.appendSection("AI workflow setup source", [
        `source: ${input.source.kind}`,
        `accepted at: ${input.acceptedAt}`,
        ...(input.source.kind === "fresh_comment"
            ? [`comment id: ${input.source.comment.id}`]
            : []),
    ].join("\n"));
}
function formatJsonForIssueLog(value) {
    return JSON.stringify(value, null, 2) ?? String(value);
}
async function resolveRunnableWorkflowSetupSource(input) {
    return (0, config_scan_helpers_1.resolveRunnableWorkflowSetupRequest)({
        ticketTracker: input.context.freshTicketTracker,
        config: input.context.config,
        issue: input.issue,
        scanState: input.scanState,
    });
}
async function buildWorkflowSetupPlanSpec(input) {
    return (0, config_explicit_command_support_1.buildAcceptedWorkflowUpdatePlanSpec)({
        repoRoot: (0, workflow_template_root_1.getWorkflowTemplateRepoRoot)(input.context),
        config: input.context.config,
        ticketTracker: input.context.freshTicketTracker,
        issue: input.issue,
        comments: input.scanState.comments,
        stickyState: input.scanState.stickyState,
        command: input.workflowCommand,
        acceptedAt: input.acceptedAt,
        scannedInputCursor: input.source.kind === "fresh_comment" ? input.source.cursor : null,
        currentWorkflowStateCommentId: input.scanState.currentWorkflowStateCommentId,
        currentNeedsHumanReason: input.scanState.currentNeedsHumanReason,
        responseLanguage: input.context.config.i18n.defaultLanguage,
        workflowLabels: input.context.config.ticketTracker.workflowLabels,
        ...(input.source.kind === "tracker_issue_body"
            ? {
                commentCursorPolicyMode: publisher_1.WORKFLOW_COMMENT_CURSOR_POLICY_MODES.preserve,
            }
            : {
                handoffVisibleUpdateDedupeCursor: input.source.cursor,
                visibleUpdateDedupeCursor: input.source.cursor,
            }),
        feedbackMode: "silent",
    });
}
function buildWorkflowSetupHandoffPlanSpec(input) {
    const nextWorkflowState = buildWorkflowSetupHandoffState({
        config: input.context.config,
        scanState: input.scanState,
        setupResult: input.setupResult,
    });
    return (0, config_publish_spec_support_1.buildServiceRuntimeProjectedPublishSpec)({
        decisionKind: "commandless",
        issue: input.issue,
        responseLanguage: input.responseLanguage,
        workflowState: nextWorkflowState,
        scannedInputCursor: input.source.kind === "fresh_comment" ? input.source.cursor : null,
        commentCursorPolicyMode: input.source.kind === "tracker_issue_body"
            ? publisher_1.WORKFLOW_COMMENT_CURSOR_POLICY_MODES.preserve
            : publisher_1.WORKFLOW_COMMENT_CURSOR_POLICY_MODES.advanceToPublishedCommentIfSafe,
        visibleUpdateDedupeCursor: input.source.kind === "fresh_comment" ? input.source.cursor : undefined,
        workflowLabels: input.context.config.ticketTracker.workflowLabels,
        nextWorkflowSnapshot: (0, workflow_projection_support_1.withWorkflowStatus)(input.issue.workflowState, types_1.WORKFLOW_STATUSES.aiNeedsHuman),
        previousWorkflowState: input.scanState.stickyState,
        nextWorkflowState,
        previousNeedsHumanReason: input.scanState.currentNeedsHumanReason,
        nextNeedsHumanReason: publisher_events_1.WORKFLOW_NEEDS_HUMAN_REASONS.question,
        visibleUpdate: (0, visible_update_builders_1.buildWorkflowVisibleUpdate)({
            event: publisher_events_1.WORKFLOW_VISIBLE_EVENTS.humanAttentionRequested,
            summary: input.setupResult.summary,
            next: (0, catalog_1.translate)(input.responseLanguage, "run.presentation.failNext"),
            needsHumanReason: publisher_events_1.WORKFLOW_NEEDS_HUMAN_REASONS.question,
        }),
    });
}
function buildWorkflowSetupHandoffState(input) {
    const previousState = input.setupResult.workflowState ?? input.scanState.stickyState;
    return (0, config_decision_approval_support_1.materializeServiceRuntimeWorkflowState)({
        config: input.config,
        previousState,
        workflowSurface: previousState?.workflowSurface ?? "issue",
        needsHumanReason: publisher_events_1.WORKFLOW_NEEDS_HUMAN_REASONS.question,
    });
}
function resolveWorkflowSetupAcceptedAt(source, issue) {
    return source.kind === "fresh_comment"
        ? source.comment.createdAt
        : issue.updatedAt;
}
function isWorkflowSetupAutofillCapabilityMissing(error) {
    return (error instanceof Error &&
        error.message === "AI workflow option autofill handler missing");
}
function isNonMutatingWorkflowSetupPlan(planSpec, stickyState) {
    return (planSpec.kind === "publish_spec" &&
        planSpec.workflowState === stickyState &&
        planSpec.workflowProjection === undefined);
}
function buildWorkflowSetupDeferredSummary(input) {
    const triedProfiles = input.setupResult.triedProfiles.map((profile) => (0, freshness_1.renderWorkerAttemptLabel)(profile.workerName));
    const presentation = (0, presentation_1.buildDeferredPresentation)(input.responseLanguage, input.setupResult.cooldownUntil, triedProfiles);
    return (0, results_1.buildRunCliSummary)({
        issue: input.issue,
        outcome: constants_1.RUN_ISSUE_OUTCOMES.deferred,
        responseLanguage: input.responseLanguage,
        summary: presentation.summary,
        commentUrl: null,
        prUrl: null,
        nextStep: presentation.next,
        deferredReason: input.setupResult.reason,
        triedProfiles,
        cooldownUntil: input.setupResult.cooldownUntil,
    });
}
function buildWorkflowSetupFailedSummary(input) {
    const failureSummary = (0, results_1.resolveFailureSummary)(input.error, input.responseLanguage, input.issue.displayId);
    return (0, results_1.buildRunCliSummary)({
        issue: input.issue,
        outcome: constants_1.RUN_ISSUE_OUTCOMES.failed,
        responseLanguage: input.responseLanguage,
        summary: failureSummary.public,
        commentUrl: null,
        prUrl: null,
        nextStep: (0, catalog_1.translate)(input.responseLanguage, "run.needsHuman.failure.next"),
    });
}
