"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.runIssueCommand = runIssueCommand;
exports.runIssueApproveCommand = runIssueApproveCommand;
exports.runIssueStartCommand = runIssueStartCommand;
exports.runIssueDisabledRuleCommand = runIssueDisabledRuleCommand;
exports.runIssueFollowupCommand = runIssueFollowupCommand;
exports.runIssueCreateCommand = runIssueCreateCommand;
exports.runIssueListCommand = runIssueListCommand;
exports.runIssueSearchCommand = runIssueSearchCommand;
exports.runIssueShowCommand = runIssueShowCommand;
exports.runIssueBroadcastCommand = runIssueBroadcastCommand;
exports.runIssueUnlockCommand = runIssueUnlockCommand;
// biome-ignore lint/nursery/noExcessiveLinesPerFile: Issue command behavior remains grouped around tracker operations and shared rendering helpers.
const node_fs_1 = require("node:fs");
const promises_1 = require("node:fs/promises");
const control_plane_config_1 = require("../config/control-plane-config");
const markdown_output_1 = require("../core/markdown-output");
const remote_base_branch_1 = require("../git/remote-base-branch");
const catalog_1 = require("../i18n/catalog");
const issue_report_1 = require("../issues/issue-report");
const types_1 = require("../issues/types");
const factory_1 = require("../platform/auth/factory");
const constants_1 = require("../platform/constants");
const provider_resolution_1 = require("../platform/provider-resolution");
const factory_2 = require("../platform/repository-host/factory");
const scoped_repository_host_client_1 = require("../platform/repository-host/scoped-repository-host-client");
const factory_3 = require("../platform/ticket-tracker/factory");
const scoped_ticket_tracker_client_1 = require("../platform/ticket-tracker/scoped-ticket-tracker-client");
const workflow_labels_1 = require("../platform/ticket-tracker/workflow-labels");
const types_2 = require("../platform/workflow-state/types");
const run_once_cycle_1 = require("../run/run-once-cycle");
const issue_creation_publication_1 = require("../run/run-once-cycle/issue-creation-publication");
const shared_1 = require("../run/run-once-cycle/shared");
const terminal_followup_1 = require("../run/run-once-cycle/terminal-followup");
const approval_instructions_1 = require("../workflows/approval-instructions");
const assignee_resolution_1 = require("../workflows/assignee-resolution");
const display_labels_1 = require("../workflows/display-labels");
const plan_progress_1 = require("../workflows/plan-progress");
const publisher_1 = require("../workflows/publisher");
const state_1 = require("../workflows/state");
const workflow_state_read_support_1 = require("../workflows/workflow-state-read-support");
const draft_file_support_1 = require("./draft-file-support");
const issue_create_1 = require("./issue-create");
const issue_list_web_1 = require("./issue-list-web");
const issue_related_pull_request_1 = require("./issue-related-pull-request");
const issue_rendering_1 = require("./issue-rendering");
const issue_show_view_model_1 = require("./issue-show-view-model");
const log_inspection_1 = require("./log-inspection");
async function runIssueCommand(cwd, options) {
    switch (options.action) {
        case "approve":
            return runIssueApproveCommand(cwd, options);
        case "start":
            return runIssueStartCommand(cwd, options);
        case "disable":
        case "enable":
            return runIssueDisabledRuleCommand(cwd, options);
        case "create":
            return runIssueCreateCommand(cwd, options);
        case "followup":
            return runIssueFollowupCommand(cwd, options);
        case "list":
            return runIssueListCommand(cwd, options);
        case "search":
            return runIssueSearchCommand(cwd, options);
        case "show":
            return runIssueShowCommand(cwd, options);
        case "broadcast":
            return runIssueBroadcastCommand(cwd, options);
        case "log-list":
            return runIssueLogListCommand(cwd);
        case "log-show":
            return runIssueLogShowCommand(cwd, options);
        case "log-search":
            return runIssueLogSearchCommand(cwd, options);
        case "unlock":
            return runIssueUnlockCommand(cwd, options);
    }
}
async function runIssueApproveCommand(cwd, options) {
    const clients = await loadIssueApprovalCommandClients(cwd);
    const issue = await clients.ticketTracker.getIssue(options.issueId);
    await assertIssueCommandAssignee({
        clients,
        issue,
        singleAssigneeKey: "issue.command.approve.singleAssigneeRequired",
        assigneeOnlyKey: "issue.command.approve.assigneeOnly",
    });
    await clients.ticketTracker.createComment(issue.id, (0, approval_instructions_1.getIssueApproveCommentCommand)());
    console.log((0, catalog_1.translate)(clients.locale, "issue.command.approve.summary", {
        displayId: issue.displayId,
    }));
    return 0;
}
async function runIssueStartCommand(cwd, options) {
    const clients = await loadIssueApprovalCommandClients(cwd);
    const issue = await clients.ticketTracker.getIssue(options.issueId);
    await assertIssueCommandAssignee({
        clients,
        issue,
        singleAssigneeKey: "issue.command.start.singleAssigneeRequired",
        assigneeOnlyKey: "issue.command.start.assigneeOnly",
    });
    const workflowState = await (0, workflow_state_read_support_1.resolvePersistedIssueWorkflowState)(clients.ticketTracker, issue.id);
    if (workflowState === null) {
        throw new Error((0, catalog_1.translate)(clients.locale, "issue.command.start.invalidWorkflowState", {
            displayId: issue.displayId,
        }));
    }
    if (!(0, state_1.isWorkflowAwaitingStartApproval)(workflowState)) {
        throw new Error((0, catalog_1.translate)(clients.locale, "issue.command.start.notStartApproval", {
            displayId: issue.displayId,
        }));
    }
    if (!(0, plan_progress_1.hasStartableWorkflowPlan)(workflowState)) {
        throw new Error((0, catalog_1.translate)(clients.locale, "issue.command.start.invalidWorkflowState", {
            displayId: issue.displayId,
        }));
    }
    await clients.ticketTracker.createComment(issue.id, (0, approval_instructions_1.getIssueStartCommentCommand)());
    console.log((0, catalog_1.translate)(clients.locale, "issue.command.start.summary", {
        displayId: issue.displayId,
    }));
    return 0;
}
async function loadDisabledRuleIssue(ticketTracker, issueId) {
    try {
        return {
            kind: "loaded",
            issueId,
            issue: await ticketTracker.getIssue(issueId),
        };
    }
    catch (error) {
        return {
            kind: "failed",
            issueId,
            error,
        };
    }
}
async function runIssueDisabledRuleCommand(cwd, options) {
    const clients = await loadIssueCommandClients(cwd);
    const issueLoadResults = await Promise.all(dedupeIssueIds(options.issueIds).map(async (issueId) => loadDisabledRuleIssue(clients.ticketTracker, issueId)));
    let changedIssueCount = 0;
    let failureCount = 0;
    for (const result of sortDisabledRuleIssueLoadResults(issueLoadResults)) {
        if (result.kind === "failed") {
            failureCount += 1;
            console.log(renderDisabledRuleLoadFailure(result.issueId, result.error, clients.locale));
            continue;
        }
        const currentSnapshot = result.issue.workflowState;
        try {
            if (!result.issue.isOpen) {
                throw new Error((0, catalog_1.translate)(clients.locale, "issue.command.disabledRule.closedIssue", {
                    displayId: result.issue.displayId,
                }));
            }
            const nextSnapshot = buildDisabledRuleNextSnapshot(currentSnapshot, options.action);
            const changed = !(0, types_2.isSameWorkflowStateSnapshot)(currentSnapshot, nextSnapshot);
            if (changed) {
                await clients.ticketTracker.syncWorkflowState({
                    issueId: result.issue.id,
                    previous: currentSnapshot,
                    next: nextSnapshot,
                    ...(result.issue.labelNames !== undefined
                        ? { currentLabelNames: result.issue.labelNames }
                        : {}),
                });
                changedIssueCount += 1;
            }
            console.log(renderDisabledRuleLine({
                issue: result.issue,
                action: options.action,
                currentSnapshot,
                nextSnapshot,
                workflowLabels: clients.workflowLabels,
                locale: clients.locale,
            }));
        }
        catch (error) {
            failureCount += 1;
            console.log(renderDisabledRuleIssueFailure(result.issue, error, clients.locale));
        }
    }
    console.log((0, catalog_1.translate)(clients.locale, `issue.command.${options.action}.summary`, {
        count: changedIssueCount,
        failedSuffix: failureCount > 0
            ? (0, catalog_1.translate)(clients.locale, "issue.command.disabledRule.failedSuffix", {
                count: failureCount,
            })
            : "",
    }));
    return failureCount > 0 ? 1 : 0;
}
async function assertIssueCommandAssignee(input) {
    const { clients, issue } = input;
    const assigneeGate = (0, assignee_resolution_1.resolveWorkflowAssigneeGate)({
        assignees: issue.assignees,
    });
    if (assigneeGate.kind !== "ok") {
        throw new Error((0, catalog_1.translate)(clients.locale, input.singleAssigneeKey, {
            displayId: issue.displayId,
        }));
    }
    const currentUser = await clients.ticketTracker.getAuthenticatedUserLogin();
    if (currentUser !== assigneeGate.assignee) {
        throw new Error((0, catalog_1.translate)(clients.locale, input.assigneeOnlyKey, {
            displayId: issue.displayId,
            assignee: assigneeGate.assignee,
            currentUser,
        }));
    }
}
async function loadIssueApprovalCommandClients(cwd) {
    const { config } = (0, provider_resolution_1.resolveSupportedProviders)(await (0, control_plane_config_1.loadConfig)(cwd));
    const authProvider = (0, factory_1.createAuthProvider)(config);
    const rawTicketTracker = await (0, factory_3.createTicketTrackerClient)(config, authProvider);
    return {
        locale: config.i18n.defaultLanguage,
        ticketTracker: (0, scoped_ticket_tracker_client_1.createScopedTicketTrackerClient)(rawTicketTracker),
    };
}
async function runIssueFollowupCommand(cwd, options) {
    const clients = await loadIssueCommandClients(cwd);
    const sourceIssue = await clients.ticketTracker.getIssue(options.issueId);
    const sourceWorkflowState = await (0, workflow_state_read_support_1.resolvePersistedIssueWorkflowState)(clients.ticketTracker, sourceIssue.id);
    const outcome = await (0, terminal_followup_1.publishSourceFollowupIssueIfNeeded)({
        context: {
            cwd,
            config: clients.config,
            ticketTracker: clients.ticketTracker,
        },
        workflowLabels: clients.workflowLabels,
        sourceIssue,
        sourceWorkflowState,
        ...(options.workflowSelector !== undefined
            ? { explicitSelector: options.workflowSelector }
            : {}),
        ...(options.prompt !== undefined
            ? { followupRequestBody: options.prompt }
            : {}),
        responseLanguage: clients.locale,
        forceProposalPolicy: "always",
        forceProposalApproval: "auto",
        materializeWorkflowState: !options.dryRun,
        dryRun: options.dryRun,
        clearRequestLabelOnSuccess: true,
        publishFeedback: !options.dryRun,
    });
    if (options.dryRun !== true && outcome.workflowState !== null) {
        await (0, terminal_followup_1.publishFollowupSourceWorkflowState)({
            context: {
                cwd,
                config: clients.config,
                ticketTracker: clients.ticketTracker,
            },
            sourceIssue,
            workflowState: outcome.workflowState,
            responseLanguage: clients.locale,
            clearRequestLabel: outcome.shouldClearRequestLabel,
        });
    }
    const result = outcome.result;
    if (result === null) {
        return 0;
    }
    switch (result.kind) {
        case "created":
        case "reused":
            console.log((0, catalog_1.translate)(clients.locale, "issue.command.followup.created", {
                displayId: result.issue.displayId,
                url: result.issue.url,
            }));
            return 0;
        case "dry_run":
            console.log(result.reason);
            return 0;
        case "failed":
        case "skipped":
            console.error(result.reason);
            return 1;
    }
}
// biome-ignore lint/complexity/noExcessiveLinesPerFunction: Issue creation keeps draft resolution, review, and publish sequencing in one auditable flow.
async function runIssueCreateCommand(cwd, options, deps = {}) {
    const clients = await loadIssueCommandClients(cwd);
    const preparedAt = new Date().toISOString();
    const acceptedAt = preparedAt;
    let draft;
    let assignees;
    let disabled;
    let milestoneRef;
    let projectRef;
    let baseLabelNames;
    if (options.mode === "apply-draft") {
        const source = await loadIssueCreateDraftFile(options.applyDraftPath, clients.locale);
        (0, issue_create_1.assertIssueCreateDraftMatchesTracker)(source, clients.config, clients.locale);
        options.validateDraft?.(source);
        draft = {
            title: source.title,
            body: source.body,
            selectedIssueTemplatePath: source.selectedIssueTemplatePath ?? null,
            sourcePrompt: source.sourcePrompt ?? null,
            ...(source.workflowOptions !== undefined
                ? { workflowOptions: source.workflowOptions }
                : {}),
        };
        assignees = source.assignees;
        disabled = source.disabled;
        milestoneRef = source.milestoneRef;
        projectRef = source.projectRef;
        baseLabelNames = (0, issue_create_1.stripManagedIssueCreateLabelNames)(source.labels, clients.workflowLabels);
    }
    else {
        draft = await (0, issue_create_1.resolveIssueCreateDraft)(cwd, clients, options, acceptedAt);
        assignees = await (0, issue_create_1.resolveIssueCreateAssignees)(clients.ticketTracker, options.assignees);
        disabled = options.disabled;
        milestoneRef = options.milestoneRef;
        projectRef = options.projectRef;
        baseLabelNames = (0, issue_create_1.stripManagedIssueCreateLabelNames)(options.labels, clients.workflowLabels);
    }
    const issueBody = draft.body;
    const initialWorkflowState = (0, issue_create_1.buildIssueCreateInitialWorkflowState)({
        disabled,
    });
    const workflowState = await (0, issue_create_1.buildIssueCreateWorkflowState)(cwd, clients, draft.workflowOptions, acceptedAt);
    if (options.mode === "apply-draft" || options.saveDraft !== true) {
        await assertIssueCreateRemoteBaseBranch(cwd, clients, workflowState);
    }
    const workflowProjection = (0, issue_create_1.buildIssueCreateWorkflowProjection)(clients.workflowLabels, initialWorkflowState, workflowState, disabled);
    const labelNames = (0, issue_create_1.buildIssueCreateLabelNames)(clients.workflowLabels, baseLabelNames, workflowProjection);
    const issuePublicationPlan = (0, issue_creation_publication_1.buildCreateIssuePublicationPlan)({
        source: "cli",
        branchTarget: "effective_base_branch",
        relationship: { kind: "independent" },
        title: draft.title,
        body: issueBody,
        trackerFields: {
            assignees,
            labelNames,
            ...(milestoneRef !== undefined ? { milestoneRef } : {}),
            ...(projectRef !== undefined ? { projectRef } : {}),
        },
        workflowState,
        workflowProjection,
        newIssueFailurePolicy: "leave_created_issue",
        responseLanguage: clients.locale,
    });
    if (options.mode !== "apply-draft" && options.saveDraft === true) {
        const reusableDraft = (0, issue_create_1.buildIssueCreateDraftFile)({
            config: clients.config,
            preparedAt: acceptedAt,
            draft,
            assignees,
            labels: baseLabelNames,
            disabled,
            ...(milestoneRef !== undefined ? { milestoneRef } : {}),
            ...(projectRef !== undefined ? { projectRef } : {}),
        });
        const draftJson = (0, issue_create_1.stringifyIssueCreateDraftFile)(reusableDraft);
        const applyDraftPath = await (0, draft_file_support_1.writeMachineLocalReusableDraft)({
            draftJson,
            trackedProject: clients.config,
            command: "issue-create",
            preparedAt: acceptedAt,
            title: draft.title,
            ...(deps.homeDirectory !== undefined
                ? { homeDirectory: deps.homeDirectory }
                : {}),
        });
        console.log(renderIssueCreateDraftReviewSummary({
            draft,
            assignees,
            labelNames,
            ...(milestoneRef !== undefined ? { milestoneRef } : {}),
            ...(projectRef !== undefined ? { projectRef } : {}),
            workflowState,
            workflowStatus: formatIssueCreateWorkflowStatus(clients.workflowLabels, workflowProjection, initialWorkflowState),
            workflowDisplayCatalog: clients.workflowDisplayCatalog,
            locale: clients.locale,
            applyDraftPath,
        }));
        return 0;
    }
    const publisher = (0, publisher_1.createWorkflowPublisher)({
        repoRoot: cwd,
        ticketTrackerKind: clients.config.ticketTracker.kind,
        displayTimeZone: clients.config.i18n.displayTimeZone,
        workflowLabels: clients.workflowLabels,
        ticketTracker: clients.ticketTracker,
    });
    const publication = await (0, issue_creation_publication_1.executeIssuePublicationPlans)({
        publisher,
        plans: [issuePublicationPlan],
        eventHooks: {
            repoRoot: cwd,
            config: clients.config,
        },
    });
    const published = publication.executions[0]?.publication;
    if (published === undefined || published === null) {
        throw new Error("Issue creation publication returned no target issue.");
    }
    const issue = publication.executions[0]?.issue ?? published.targetIssue;
    console.log((0, issue_create_1.renderIssueCreateSummary)(issue, published.targetWorkflowState, formatIssueCreateWorkflowStatus(clients.workflowLabels, workflowProjection, published.targetWorkflowProjection ?? initialWorkflowState), clients.locale, clients.workflowDisplayCatalog));
    return 0;
}
async function assertIssueCreateRemoteBaseBranch(cwd, clients, workflowState) {
    (0, remote_base_branch_1.assertRemoteBaseBranchPresent)(await (0, remote_base_branch_1.checkRemoteBaseBranchRef)({
        cwd,
        locale: clients.locale,
        remoteName: clients.config.repositoryHost.remoteName,
        projectRef: clients.config.repositoryHost.projectRef,
        credentials: await (0, remote_base_branch_1.tryResolveRemoteBaseBranchGitCredentials)(clients.authProvider, clients.config.repositoryHost),
        baseBranch: workflowState?.baseBranch ?? clients.config.repositoryHost.baseBranch,
    }));
}
async function runIssueListCommand(cwd, options) {
    if (options.web === true) {
        const { config } = (0, provider_resolution_1.resolveSupportedProviders)(await (0, control_plane_config_1.loadConfig)(cwd));
        const resolveGiteaLabelIds = config.ticketTracker.kind === "gitea"
            ? async (labelNames) => {
                const authProvider = (0, factory_1.createAuthProvider)(config);
                const credential = await authProvider.getTicketTrackerToken(config.ticketTracker);
                return (0, issue_list_web_1.resolveGiteaIssueListLabelIds)({
                    config,
                    credential,
                    labelNames,
                    locale: config.i18n.defaultLanguage,
                });
            }
            : undefined;
        const url = await (0, issue_list_web_1.openIssueListWeb)({
            config,
            options,
            locale: config.i18n.defaultLanguage,
            ...(resolveGiteaLabelIds !== undefined ? { resolveGiteaLabelIds } : {}),
        });
        console.log((0, catalog_1.translate)(config.i18n.defaultLanguage, "issue.command.list.webOpened", {
            url,
        }));
        return 0;
    }
    const clients = await loadIssueCommandClients(cwd);
    const reportOptions = await resolveIssueListReportOptions(clients, options);
    const contexts = await loadIssueReportData(clients, reportOptions);
    if (contexts.length === 0 &&
        reportOptions.format !== types_1.ISSUE_REPORT_FORMATS.markdown) {
        console.log((0, issue_rendering_1.renderEmptyIssueReport)(reportOptions, clients.locale));
        return 0;
    }
    console.log(formatIssueMarkdownCliOutput((0, issue_rendering_1.renderIssueReport)(contexts, clients.workflowLabels, reportOptions, clients.locale, clients.config.i18n.displayTimeZone, clients.workflowDisplayCatalog), reportOptions.format));
    return 0;
}
async function runIssueSearchCommand(cwd, options) {
    const clients = await loadIssueSearchCommandContext(cwd);
    const renderOptions = {
        ...options,
    };
    const issues = selectIssueSearchResults(await clients.ticketTracker.searchIssueRecords({
        mode: options.mode,
        text: options.text,
        state: options.state ?? issue_rendering_1.DEFAULT_ISSUE_STATE,
        limit: options.limit,
        includePullRequests: options.includePullRequests,
    }), options.limit);
    if (issues.length === 0 && options.format !== types_1.ISSUE_REPORT_FORMATS.markdown) {
        console.log((0, issue_rendering_1.renderEmptyIssueSearchResults)(renderOptions, clients.locale));
        return 0;
    }
    console.log(formatIssueMarkdownCliOutput((0, issue_rendering_1.renderIssueSearchResults)(issues, renderOptions, clients.locale, clients.config.i18n.displayTimeZone), options.format));
    return 0;
}
async function resolveIssueListReportOptions(clients, options) {
    const { assignees: requestedAssignees, me, web: _web, ...renderOptions } = options;
    const assignees = [...(requestedAssignees ?? [])];
    if (me === true) {
        const currentUser = (await clients.ticketTracker.getAuthenticatedUserLogin()).trim();
        if (currentUser.length === 0) {
            throw new Error((0, catalog_1.translate)(clients.locale, "issue.command.list.meLoginRequired"));
        }
        assignees.push(currentUser);
    }
    const resolvedAssignees = dedupeIssueListAssignees(assignees);
    return {
        ...renderOptions,
        ...(resolvedAssignees.length > 0 ? { assignees: resolvedAssignees } : {}),
    };
}
async function runIssueShowCommand(cwd, options) {
    const clients = await loadIssueCommandClients(cwd);
    const viewModel = await (0, issue_show_view_model_1.loadIssueShowViewModel)(clients, options);
    console.log(formatIssueMarkdownCliOutput((0, issue_rendering_1.renderIssueShow)(viewModel, options.format, clients.locale, clients.config.i18n.displayTimeZone), options.format));
    return 0;
}
function formatIssueMarkdownCliOutput(output, format) {
    return format === types_1.ISSUE_REPORT_FORMATS.markdown
        ? (0, markdown_output_1.appendMarkdownAgentRenderInstruction)(output)
        : output;
}
async function runIssueBroadcastCommand(cwd, options) {
    const clients = await loadIssueCommandClients(cwd);
    const publisher = (0, publisher_1.createWorkflowPublisher)({
        repoRoot: cwd,
        ticketTrackerKind: clients.config.ticketTracker.kind,
        displayTimeZone: clients.config.i18n.displayTimeZone,
        workflowLabels: clients.workflowLabels,
        ticketTracker: clients.ticketTracker,
    });
    const isDryRun = options.dryRun === true;
    const issues = await resolveBroadcastTargets(clients, options.target);
    const message = await loadBroadcastMessage(options.message);
    if (issues.length === 0) {
        console.log((0, catalog_1.translate)(clients.locale, "issue.command.broadcast.noTargets"));
        return 0;
    }
    let failureCount = 0;
    for (const issue of issues) {
        try {
            const currentSnapshot = issue.workflowState;
            const nextSnapshot = buildBroadcastNextSnapshot(issue);
            if (!isDryRun) {
                await publisher.publishWorkflow({
                    target: {
                        kind: "existing_issue",
                        issueId: issue.id,
                        preloadedIssue: issue,
                    },
                    workflowState: null,
                    ...((0, types_2.isSameWorkflowStateSnapshot)(currentSnapshot, nextSnapshot)
                        ? {}
                        : {
                            workflowProjection: {
                                previous: currentSnapshot,
                                next: nextSnapshot,
                            },
                        }),
                    visibleUpdate: {
                        kind: "feedback",
                        summary: message,
                        dedupe: false,
                    },
                    commentCursorPolicy: {
                        mode: publisher_1.WORKFLOW_COMMENT_CURSOR_POLICY_MODES.preserve,
                    },
                    responseLanguage: clients.locale,
                });
            }
            console.log(renderBroadcastLine(issue, currentSnapshot, nextSnapshot, isDryRun, clients.workflowLabels, clients.locale));
        }
        catch (error) {
            failureCount += 1;
            console.log(renderBroadcastFailure(issue, error, clients.locale));
        }
    }
    if (isDryRun) {
        console.log((0, catalog_1.translate)(clients.locale, "issue.command.broadcast.dryRunSummary", {
            count: issues.length,
        }));
        return 0;
    }
    console.log((0, catalog_1.translate)(clients.locale, "issue.command.broadcast.summary", {
        count: issues.length,
        failedSuffix: failureCount > 0
            ? (0, catalog_1.translate)(clients.locale, "issue.command.broadcast.failedSuffix", {
                count: failureCount,
            })
            : "",
    }));
    return failureCount > 0 ? 1 : 0;
}
async function runIssueUnlockCommand(cwd, options) {
    const clients = await loadIssueCommandClients(cwd);
    const unlockedIssueCount = await (0, run_once_cycle_1.unlockAiRunningIssues)(clients.ticketTracker, {
        trackedProject: {
            i18n: clients.config.i18n,
            repositoryHost: clients.config.repositoryHost,
            ticketTracker: clients.config.ticketTracker,
        },
        repoRoot: cwd,
        displayTimeZone: clients.config.i18n.displayTimeZone,
        issueIds: options.issueIds,
    });
    console.log((0, catalog_1.translate)(clients.locale, "issue.command.unlock.summary", {
        count: unlockedIssueCount,
    }));
    return 0;
}
async function loadIssueCommandClients(cwd) {
    const { config } = (0, provider_resolution_1.resolveSupportedProviders)(await (0, control_plane_config_1.loadConfig)(cwd));
    const authProvider = (0, factory_1.createAuthProvider)(config);
    const [rawTicketTracker, rawRepositoryHost, workflowDisplayCatalog] = await Promise.all([
        (0, factory_3.createTicketTrackerClient)(config, authProvider),
        (0, factory_2.createRepositoryHostClient)(config, authProvider),
        (0, display_labels_1.tryLoadWorkflowDisplayCatalog)(cwd, config.i18n.defaultLanguage),
    ]);
    const ticketTracker = (0, scoped_ticket_tracker_client_1.createScopedTicketTrackerClient)(rawTicketTracker);
    const repositoryHost = (0, scoped_repository_host_client_1.createScopedRepositoryHostClient)(rawRepositoryHost);
    return {
        config,
        locale: config.i18n.defaultLanguage,
        authProvider,
        workflowLabels: config.ticketTracker.workflowLabels,
        workflowDisplayCatalog,
        ticketTracker,
        repositoryHost,
    };
}
async function loadIssueSearchCommandContext(cwd) {
    const { config } = (0, provider_resolution_1.resolveSupportedProviders)(await (0, control_plane_config_1.loadConfig)(cwd));
    const authProvider = (0, factory_1.createAuthProvider)(config);
    const rawTicketTracker = await (0, factory_3.createTicketTrackerClient)(config, authProvider);
    return {
        config,
        locale: config.i18n.defaultLanguage,
        ticketTracker: (0, scoped_ticket_tracker_client_1.createScopedTicketTrackerClient)(rawTicketTracker),
    };
}
async function loadIssueLogCommandContext(cwd) {
    const { config } = (0, provider_resolution_1.resolveSupportedProviders)(await (0, control_plane_config_1.loadConfig)(cwd));
    return {
        config,
        locale: config.i18n.defaultLanguage,
    };
}
async function runIssueLogListCommand(cwd) {
    const { config, locale } = await loadIssueLogCommandContext(cwd);
    const issueIds = await (0, log_inspection_1.listTrackedProjectIssueLogIds)(config);
    if (issueIds.length === 0) {
        console.log((0, log_inspection_1.renderEmptyIssueLogList)(locale));
        return 0;
    }
    console.log((0, log_inspection_1.formatIssueLogList)(issueIds));
    return 0;
}
async function runIssueLogShowCommand(cwd, options) {
    const { config, locale } = await loadIssueLogCommandContext(cwd);
    const text = await (0, log_inspection_1.readIssueLogText)(config, options.issueId);
    if (text === null) {
        console.log((0, log_inspection_1.renderEmptyIssueLogShow)(locale, options.issueId));
        return 0;
    }
    process.stdout.write((0, log_inspection_1.sliceTextTail)(text, options.tail));
    return 0;
}
async function runIssueLogSearchCommand(cwd, options) {
    const { config, locale } = await loadIssueLogCommandContext(cwd);
    const blocks = await (0, log_inspection_1.searchTrackedProjectIssueLogs)(config, options.query, options.context);
    if (blocks.length === 0) {
        console.log((0, log_inspection_1.renderEmptyIssueLogSearch)(locale));
        return 0;
    }
    console.log((0, log_inspection_1.renderIssueLogSearchBlocks)(blocks, locale));
    return 0;
}
async function loadBroadcastMessage(message) {
    if (message.kind === "text") {
        return message.text;
    }
    if (message.path === "-") {
        return (0, node_fs_1.readFileSync)(0, "utf8");
    }
    return (0, promises_1.readFile)(message.path, "utf8");
}
async function loadIssueCreateDraftFile(applyDraftPath, locale) {
    return (0, issue_create_1.parseIssueCreateDraftFile)(await (0, draft_file_support_1.readReusableDraftFile)(applyDraftPath), locale);
}
function renderIssueCreateDraftReviewSummary(input) {
    const lines = [
        (0, catalog_1.translate)(input.locale, "issue.command.create.draftReview.heading"),
        (0, catalog_1.translate)(input.locale, "issue.command.create.draftReview.title", {
            value: input.draft.title,
        }),
        (0, catalog_1.translate)(input.locale, "issue.command.create.draftReview.issueTemplate", {
            value: input.draft.selectedIssueTemplatePath ??
                (0, catalog_1.translate)(input.locale, "workflow.runContext.none"),
        }),
        (0, catalog_1.translate)(input.locale, "issue.command.create.status", {
            value: input.workflowStatus,
        }),
        (0, catalog_1.translate)(input.locale, "issue.command.create.workflow", {
            value: (0, issue_create_1.resolveIssueCreateWorkflowLabel)({
                workflowState: input.workflowState,
                locale: input.locale,
                workflowDisplayCatalog: input.workflowDisplayCatalog,
            }),
        }),
        (0, issue_create_1.renderIssueCreatePlanLine)(input.workflowState, input.locale),
        (0, catalog_1.translate)(input.locale, "issue.command.create.draftReview.assignees", {
            value: formatOptionalList(input.assignees, input.locale),
        }),
        (0, catalog_1.translate)(input.locale, "issue.command.create.draftReview.labels", {
            value: formatOptionalList(input.labelNames, input.locale),
        }),
    ].filter((line) => line !== null);
    if (input.milestoneRef !== undefined) {
        lines.push((0, catalog_1.translate)(input.locale, "issue.command.create.draftReview.milestone", {
            value: input.milestoneRef,
        }));
    }
    if (input.projectRef !== undefined) {
        lines.push((0, catalog_1.translate)(input.locale, "issue.command.create.draftReview.project", {
            value: input.projectRef,
        }));
    }
    lines.push((0, catalog_1.translate)(input.locale, "issue.command.create.draftReview.savedDraft", {
        value: input.applyDraftPath,
    }));
    lines.push("", (0, catalog_1.translate)(input.locale, "issue.command.create.draftReview.body"), input.draft.body);
    return lines.join("\n");
}
function formatOptionalList(values, locale) {
    return values.length === 0
        ? (0, catalog_1.translate)(locale, "workflow.runContext.none")
        : values.join(", ");
}
async function resolveBroadcastTargets(clients, target) {
    switch (target.kind) {
        case "issue": {
            const issues = await Promise.all(dedupeIssueIds(target.issueIds).map(async (issueId) => {
                const issue = await clients.ticketTracker.getIssue(issueId);
                if (!issue.isOpen) {
                    throw new Error((0, catalog_1.translate)(clients.locale, "issue.command.broadcast.closedIssue", {
                        displayId: issue.displayId,
                    }));
                }
                return issue;
            }));
            return sortIssuesById(dedupeIssues(issues));
        }
        case "open": {
            const issues = await clients.ticketTracker.listIssues({
                state: constants_1.PLATFORM_ISSUE_LIST_STATES.open,
                labelNames: target.labels,
                includeSourceBranchName: false,
            });
            const selectedIssues = issues.filter((issue) => {
                const bucket = (0, issue_report_1.getIssueReportBucket)(issue.workflowState);
                if (!target.statuses.includes(bucket)) {
                    return false;
                }
                return true;
            });
            return sortIssuesById(dedupeIssues(selectedIssues));
        }
        default: {
            const exhaustiveTarget = target;
            return exhaustiveTarget;
        }
    }
}
function buildBroadcastNextSnapshot(issue) {
    if (issue.workflowState.status === types_2.WORKFLOW_STATUSES.aiRunning) {
        return {
            status: issue.workflowState.status,
            rules: [...issue.workflowState.rules],
        };
    }
    if (issue.workflowState.status === types_2.WORKFLOW_STATUSES.aiRecurring) {
        return {
            status: issue.workflowState.status,
            rules: [...issue.workflowState.rules],
        };
    }
    if (issue.workflowState.status === types_2.WORKFLOW_STATUSES.aiScheduled) {
        return {
            status: issue.workflowState.status,
            rules: [...issue.workflowState.rules],
        };
    }
    return {
        status: types_2.WORKFLOW_STATUSES.aiReady,
        rules: [...issue.workflowState.rules],
    };
}
function buildDisabledRuleNextSnapshot(snapshot, action) {
    const rules = action === "disable"
        ? snapshot.rules.includes(types_2.WORKFLOW_RULES.aiDisabled)
            ? [...snapshot.rules]
            : [...snapshot.rules, types_2.WORKFLOW_RULES.aiDisabled]
        : snapshot.rules.filter((rule) => rule !== types_2.WORKFLOW_RULES.aiDisabled);
    return {
        status: snapshot.status,
        rules,
    };
}
function renderDisabledRuleLine(input) {
    const unchanged = (0, types_2.isSameWorkflowStateSnapshot)(input.currentSnapshot, input.nextSnapshot);
    if (unchanged) {
        return (0, catalog_1.translate)(input.locale, "issue.command.disabledRule.line.unchanged", {
            displayId: input.issue.displayId,
            state: formatWorkflowStateSnapshot(input.currentSnapshot, input.workflowLabels),
        });
    }
    return (0, catalog_1.translate)(input.locale, "issue.command.disabledRule.line.changed", {
        displayId: input.issue.displayId,
        action: (0, catalog_1.translate)(input.locale, `issue.command.${input.action}.line.action`),
        from: formatWorkflowStateSnapshot(input.currentSnapshot, input.workflowLabels),
        to: formatWorkflowStateSnapshot(input.nextSnapshot, input.workflowLabels),
    });
}
function renderDisabledRuleIssueFailure(issue, error, locale) {
    const message = error instanceof Error ? error.message : String(error);
    return (0, catalog_1.translate)(locale, "issue.command.disabledRule.line.failed", {
        displayId: issue.displayId,
        message,
    });
}
function renderDisabledRuleLoadFailure(issueId, error, locale) {
    const message = error instanceof Error ? error.message : String(error);
    return (0, catalog_1.translate)(locale, "issue.command.disabledRule.line.failed", {
        displayId: formatIssueIdForDisplay(issueId),
        message,
    });
}
function renderBroadcastLine(issue, currentSnapshot, nextSnapshot, dryRun, workflowLabels, locale) {
    const actionLabel = (0, catalog_1.translate)(locale, dryRun
        ? "issue.command.broadcast.line.wouldComment"
        : "issue.command.broadcast.line.commented");
    const transitionLabel = (0, types_2.isSameWorkflowStateSnapshot)(currentSnapshot, nextSnapshot)
        ? (0, catalog_1.translate)(locale, "issue.command.broadcast.line.unchanged", {
            state: formatWorkflowStateSnapshot(currentSnapshot, workflowLabels),
        })
        : `${formatWorkflowStateSnapshot(currentSnapshot, workflowLabels)} -> ${formatWorkflowStateSnapshot(nextSnapshot, workflowLabels)}`;
    return `${issue.displayId} ${actionLabel}; ${transitionLabel}`;
}
function renderBroadcastFailure(issue, error, locale) {
    const message = error instanceof Error ? error.message : String(error);
    return (0, catalog_1.translate)(locale, "issue.command.broadcast.line.failed", {
        displayId: issue.displayId,
        message,
    });
}
function formatWorkflowStateSnapshot(snapshot, workflowLabels) {
    return (0, workflow_labels_1.projectWorkflowLabelNames)(workflowLabels, snapshot).join(" + ");
}
function formatIssueCreateWorkflowStatus(workflowLabels, workflowProjection, fallbackSnapshot) {
    const projectedLabelNames = (0, issue_create_1.buildIssueCreateWorkflowLabelNames)(workflowLabels, workflowProjection);
    return projectedLabelNames.length > 0
        ? projectedLabelNames.join(" + ")
        : formatWorkflowStateSnapshot(fallbackSnapshot, workflowLabels);
}
function dedupeIssueIds(issueIds) {
    return [...new Set(issueIds)];
}
function dedupeIssues(issues) {
    const byId = new Map();
    for (const issue of issues) {
        byId.set(issue.id, issue);
    }
    return [...byId.values()];
}
function sortDisabledRuleIssueLoadResults(results) {
    return [...results].sort((left, right) => compareTrackerItemIds(left.issueId, right.issueId));
}
function sortIssuesById(issues) {
    return [...issues].sort((left, right) => Number(left.id) - Number(right.id));
}
function compareTrackerItemIds(left, right) {
    const leftNumber = Number(left);
    const rightNumber = Number(right);
    if (Number.isFinite(leftNumber) && Number.isFinite(rightNumber)) {
        return leftNumber - rightNumber;
    }
    return left.localeCompare(right, "en", { numeric: true });
}
function formatIssueIdForDisplay(issueId) {
    return /^\d+$/u.test(issueId) ? `#${issueId}` : issueId;
}
async function loadIssueReportData(clients, options) {
    const since = buildSinceTimestamp(options.days);
    const issues = await clients.ticketTracker.listIssues({
        state: options.state ?? issue_rendering_1.DEFAULT_ISSUE_STATE,
        labelNames: options.labels ?? [],
        ...(since ? { since } : {}),
    });
    const selectedIssues = selectIssueListReportIssues(issues, options);
    return Promise.all(selectedIssues.map(async (issue) => (0, issue_report_1.buildIssueReportContext)(issue, await (0, shared_1.loadSortedIssueComments)(clients.ticketTracker, issue.id), await (0, issue_related_pull_request_1.loadRelatedPullRequest)(clients, issue), await clients.ticketTracker.listBlockingDependencies(issue.id))));
}
function selectIssueListReportIssues(issues, options) {
    const filteredIssues = filterIssuesByAssignees(issues, options.assignees);
    const sortedIssues = filteredIssues.sort(compareByUpdatedAtDesc);
    return options.limit === undefined
        ? sortedIssues
        : sortedIssues.slice(0, options.limit);
}
function selectIssueSearchResults(issues, limit) {
    return [...issues].sort(compareByUpdatedAtDesc).slice(0, limit);
}
function filterIssuesByAssignees(issues, assignees) {
    if (assignees === undefined || assignees.length === 0) {
        return [...issues];
    }
    const assigneeSet = new Set(assignees);
    return issues.filter((issue) => issue.assignees.some((assignee) => assigneeSet.has(assignee)));
}
function dedupeIssueListAssignees(assignees) {
    return [...new Set(assignees)];
}
function buildSinceTimestamp(days) {
    if (days === undefined) {
        return undefined;
    }
    const since = new Date(Date.now() - days * 24 * 60 * 60 * 1_000);
    return since.toISOString();
}
function compareByUpdatedAtDesc(left, right) {
    return right.updatedAt.localeCompare(left.updatedAt);
}
