"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.resolveInitValues = resolveInitValues;
exports.resolveInitServiceSelection = resolveInitServiceSelection;
exports.resolveRepositoryHostRemoteName = resolveRepositoryHostRemoteName;
const control_plane_config_1 = require("../../config/control-plane-config");
const numbers_1 = require("../../core/numbers");
const structured_clone_1 = require("../../core/structured-clone");
const native_git_repository_client_1 = require("../../git/native-git-repository-client");
const remote_name_1 = require("../../git/remote-name");
const catalog_1 = require("../../i18n/catalog");
const display_time_1 = require("../../i18n/display-time");
const provider_errors_1 = require("../../platform/provider-errors");
const provider_resolution_1 = require("../../platform/provider-resolution");
const registry_1 = require("../../platform/repository-host/registry");
const registry_2 = require("../../platform/ticket-tracker/registry");
const prompts_1 = require("../prompts");
const locale_1 = require("./locale");
const project_ref_discovery_1 = require("./project-ref-discovery");
const targeted_gitea_1 = require("./targeted-gitea");
async function resolveInitValues(cwd, options, input = {}) {
    const defaults = await loadInitDefaults(cwd);
    const locale = await (0, locale_1.resolveInitLocale)(cwd, options);
    const prompter = input.prompter ?? (0, prompts_1.createCliPrompter)({ locale });
    const i18n = resolveInitI18nValues(options, defaults, locale);
    const serviceSelection = input.serviceSelection ??
        (await resolveInitServiceSelection(options, {
            cwd,
            prompter,
        }));
    const repositoryHost = await resolveRepositoryHostInitValues(cwd, options, defaults, prompter, serviceSelection.repositoryHostKind);
    const issueCompletion = await resolveIssueCompletionInitValue(options, defaults, prompter, locale);
    const ticketTracker = await resolveTicketTrackerInitValues(cwd, options, repositoryHost.projectRef, defaults.ticketTracker, prompter, serviceSelection.ticketTrackerKind);
    const pollIntervalSec = Number(options.pollIntervalSec ??
        (await prompter.input({
            label: (0, catalog_1.translate)(locale, "init.command.prompt.pollInterval"),
            defaultValue: String(defaults.pollIntervalSec),
            validate: (value) => {
                (0, numbers_1.parsePositiveInteger)((0, catalog_1.translate)(locale, "init.command.validate.pollInterval"), value, locale);
            },
        })));
    const parallelism = await resolveInitParallelismValues(options, defaults.parallelism, prompter, locale);
    const aiRunLimitsMaxRuns = Number(options.aiRunLimitsMaxRuns ??
        (await prompter.input({
            label: (0, catalog_1.translate)(locale, "init.command.prompt.aiRunLimitsMaxRuns"),
            defaultValue: String(defaults.aiRunLimits.maxRuns),
            validate: (value) => {
                (0, numbers_1.parseNonNegativeInteger)((0, catalog_1.translate)(locale, "init.command.prompt.aiRunLimitsMaxRuns"), value, locale);
            },
        })));
    const aiRunLimitsMaxHours = Object.hasOwn(options, "aiRunLimitsMaxHours")
        ? (options.aiRunLimitsMaxHours ?? null)
        : defaults.aiRunLimits.maxHours;
    const defaultPullRequest = defaults.repositoryHost.pullRequest ??
        control_plane_config_1.DEFAULT_CONFIG.repositoryHost.pullRequest;
    const reviewersInput = options.reviewers?.join(",") ??
        (await prompter.input({
            label: (0, catalog_1.translate)(locale, "init.command.prompt.defaultReviewers"),
            defaultValue: defaultPullRequest.defaultReviewers.join(","),
            validate: () => { },
        }));
    const defaultReviewers = reviewersInput
        .split(",")
        .map((value) => value.trim())
        .filter((value) => value.length > 0);
    const pullRequest = repositoryHost.pullRequest ??
        defaults.repositoryHost.pullRequest ??
        control_plane_config_1.DEFAULT_CONFIG.repositoryHost.pullRequest;
    return {
        ...defaults,
        i18n,
        issueCompletion,
        repositoryHost: {
            ...repositoryHost,
            pullRequest: {
                ...pullRequest,
                defaultReviewers,
            },
        },
        ticketTracker,
        workers: input.workers ?? defaults.workers,
        pollIntervalSec,
        parallelism,
        aiRunLimits: {
            maxRuns: aiRunLimitsMaxRuns,
            maxHours: aiRunLimitsMaxHours,
        },
    };
}
function resolveInitI18nValues(options, defaults, locale) {
    const defaultLanguage = options.language ?? defaults.i18n.defaultLanguage;
    if (!(0, catalog_1.isAppLocale)(defaultLanguage)) {
        throw new Error((0, catalog_1.translate)(locale, "cli.parser.init.invalidLanguage", {
            value: String(defaultLanguage),
        }));
    }
    const displayTimeZone = options.displayTimeZone ?? defaults.i18n.displayTimeZone;
    if (!(0, display_time_1.isSupportedTimeZone)(displayTimeZone)) {
        throw new Error((0, catalog_1.translate)(locale, "config.error.displayTimeZoneInvalid"));
    }
    return {
        defaultLanguage,
        displayTimeZone,
    };
}
async function resolveInitParallelismValues(options, defaults, prompter, locale) {
    const maxWorkers = Number(options.maxWorkers ??
        (await prompter.input({
            label: (0, catalog_1.translate)(locale, "init.command.prompt.maxWorkers"),
            defaultValue: String(defaults.maxWorkers),
            validate: (value) => {
                (0, numbers_1.parsePositiveInteger)((0, catalog_1.translate)(locale, "init.command.validate.maxWorkers"), value, locale);
            },
        })));
    (0, numbers_1.parsePositiveInteger)((0, catalog_1.translate)(locale, "init.command.validate.maxWorkers"), String(maxWorkers), locale);
    const maxIssues = Number(options.maxIssues ??
        (await prompter.input({
            label: (0, catalog_1.translate)(locale, "init.command.prompt.maxIssues"),
            defaultValue: String(defaults.maxIssues),
            validate: (value) => {
                const parsed = (0, numbers_1.parsePositiveInteger)((0, catalog_1.translate)(locale, "init.command.validate.maxIssues"), value, locale);
                validateInitParallelism(maxWorkers, parsed, locale);
            },
        })));
    (0, numbers_1.parsePositiveInteger)((0, catalog_1.translate)(locale, "init.command.validate.maxIssues"), String(maxIssues), locale);
    validateInitParallelism(maxWorkers, maxIssues, locale);
    const mode = options.parallelismMode ??
        (await prompter.select({
            label: (0, catalog_1.translate)(locale, "init.command.prompt.parallelismMode"),
            options: [
                {
                    value: "balance",
                    label: (0, catalog_1.translate)(locale, "init.command.prompt.parallelismMode.balance"),
                },
                {
                    value: "greedy",
                    label: (0, catalog_1.translate)(locale, "init.command.prompt.parallelismMode.greedy"),
                },
            ],
            defaultValue: defaults.mode,
        }));
    return { maxWorkers, maxIssues, mode };
}
function validateInitParallelism(maxWorkers, maxIssues, locale) {
    if (maxIssues <= maxWorkers) {
        return;
    }
    throw new Error((0, catalog_1.translate)(locale, "init.command.validate.parallelism"));
}
async function resolveInitServiceSelection(options, input = {}) {
    const locale = await (0, locale_1.resolveInitLocale)(input.cwd ?? process.cwd(), options);
    const prompter = input.prompter ?? (0, prompts_1.createCliPrompter)({ locale });
    if ((0, targeted_gitea_1.isTargetedGiteaInit)(options)) {
        (0, targeted_gitea_1.validateTargetedGiteaServiceOptions)(options);
        return {
            repositoryHostKind: "gitea",
            ticketTrackerKind: "gitea",
        };
    }
    return {
        repositoryHostKind: await resolveInitServiceKind(options.repositoryHostKind, {
            availableKinds: (0, registry_1.listRepositoryHostProviderKinds)(),
            defaultValue: control_plane_config_1.DEFAULT_CONFIG.repositoryHost.kind,
            label: (0, catalog_1.translate)(locale, "init.command.prompt.repositoryHostingService"),
            listLabel: (0, catalog_1.translate)(locale, "init.command.prompt.repositoryHostingServices"),
            providerType: "repositoryHost",
            resolveDisplayName: (kind) => (0, registry_1.getRepositoryHostProvider)(kind)?.auth.displayName ?? kind,
        }, locale, prompter),
        ticketTrackerKind: await resolveInitServiceKind(options.ticketTrackerKind, {
            availableKinds: (0, registry_2.listTicketTrackerProviderKinds)(),
            defaultValue: control_plane_config_1.DEFAULT_CONFIG.ticketTracker.kind,
            label: (0, catalog_1.translate)(locale, "init.command.prompt.issueTrackingService"),
            listLabel: (0, catalog_1.translate)(locale, "init.command.prompt.issueTrackingServices"),
            providerType: "ticketTracker",
            resolveDisplayName: (kind) => (0, registry_2.getTicketTrackerProvider)(kind)?.auth.displayName ?? kind,
        }, locale, prompter),
    };
}
async function resolveRepositoryHostInitValues(cwd, options, defaults, prompter, kind) {
    const locale = await (0, locale_1.resolveInitLocale)(cwd, options);
    const provider = (0, registry_1.getRepositoryHostProvider)(kind);
    const remoteName = await resolveRepositoryHostRemoteName(cwd, options, prompter);
    const repositoryHostDefaults = defaults.repositoryHost.kind === kind
        ? defaults.repositoryHost
        : control_plane_config_1.DEFAULT_CONFIG.repositoryHost;
    const pullRequestDefaults = repositoryHostDefaults.pullRequest ??
        control_plane_config_1.DEFAULT_CONFIG.repositoryHost.pullRequest;
    const projectRefDefault = (provider
        ? await (0, project_ref_discovery_1.discoverInitProjectRefFromRemote)(cwd, remoteName, {
            providerType: "repositoryHost",
            kind: provider.kind,
        })
        : null) ?? repositoryHostDefaults.projectRef;
    const projectRef = options.repositoryHostProjectRef ??
        (await prompter.input({
            label: (0, catalog_1.translate)(locale, "init.command.prompt.repositoryProject"),
            defaultValue: projectRefDefault,
            validate: (value) => validateRepositoryHostProjectRef(kind, value),
        }));
    validateRepositoryHostProjectRef(kind, projectRef);
    const baseBranch = options.repositoryHostBaseBranch ??
        (await prompter.input({
            label: (0, catalog_1.translate)(locale, "init.command.prompt.repositoryBaseBranch"),
            defaultValue: (await (0, native_git_repository_client_1.discoverGitRemoteDefaultBranch)(cwd, remoteName)) ??
                defaults.repositoryHost.baseBranch,
            validate: (value) => validateNonEmpty(locale, (0, catalog_1.translate)(locale, "init.command.validate.repositoryBaseBranch"), value),
        }));
    return {
        kind,
        projectRef,
        remoteName,
        baseBranch,
        pullRequest: {
            defaultReviewers: [...pullRequestDefaults.defaultReviewers],
        },
    };
}
async function resolveIssueCompletionInitValue(options, defaults, prompter, locale) {
    const target = options.issueCompletion?.target ??
        (await prompter.select({
            label: (0, catalog_1.translate)(locale, "init.command.prompt.issueCompletionTarget"),
            options: [
                {
                    value: "pull_request",
                    label: (0, catalog_1.translate)(locale, "init.command.prompt.issueCompletionTarget.pullRequest"),
                },
                {
                    value: "pause_on_issue",
                    label: (0, catalog_1.translate)(locale, "init.command.prompt.issueCompletionTarget.pauseOnIssue"),
                },
            ],
            defaultValue: defaults.issueCompletion.target,
        }));
    const reviewPolicy = options.issueCompletion?.pullRequest?.reviewPolicy ??
        (target === "pull_request"
            ? await prompter.select({
                label: (0, catalog_1.translate)(locale, "init.command.prompt.prReviewPolicy"),
                options: [
                    {
                        value: "if_needed",
                        label: (0, catalog_1.translate)(locale, "init.command.prompt.prReviewPolicy.ifNeeded"),
                    },
                    {
                        value: "always",
                        label: (0, catalog_1.translate)(locale, "init.command.prompt.prReviewPolicy.always"),
                    },
                    {
                        value: "never",
                        label: (0, catalog_1.translate)(locale, "init.command.prompt.prReviewPolicy.never"),
                    },
                ],
                defaultValue: defaults.issueCompletion.pullRequest.reviewPolicy,
            })
            : defaults.issueCompletion.pullRequest.reviewPolicy);
    const mergePolicy = options.issueCompletion?.pullRequest?.mergePolicy ??
        (target === "pull_request"
            ? await prompter.select({
                label: (0, catalog_1.translate)(locale, "init.command.prompt.prMergePolicy"),
                options: [
                    {
                        value: "auto",
                        label: (0, catalog_1.translate)(locale, "init.command.prompt.prMergePolicy.auto"),
                    },
                    {
                        value: "manual",
                        label: (0, catalog_1.translate)(locale, "init.command.prompt.prMergePolicy.manual"),
                    },
                ],
                defaultValue: defaults.issueCompletion.pullRequest.mergePolicy,
            })
            : defaults.issueCompletion.pullRequest.mergePolicy);
    return {
        target,
        pullRequest: {
            reviewPolicy,
            mergePolicy,
        },
    };
}
async function resolveTicketTrackerInitValues(cwd, options, repositoryHostProjectRef, defaults, prompter, kind) {
    const locale = await (0, locale_1.resolveInitLocale)(cwd, options);
    const ticketTrackerDefaults = defaults.kind === kind ? defaults : control_plane_config_1.DEFAULT_CONFIG.ticketTracker;
    const projectRef = options.ticketTrackerProjectRef ??
        (await prompter.input({
            label: (0, catalog_1.translate)(locale, "init.command.prompt.issueTrackingProject"),
            defaultValue: repositoryHostProjectRef,
            validate: (value) => validateTicketTrackerProjectRef(kind, value),
        }));
    validateTicketTrackerProjectRef(kind, projectRef);
    return {
        kind,
        projectRef,
        commentReactions: [...ticketTrackerDefaults.commentReactions],
        showStepProgressInTitles: ticketTrackerDefaults.showStepProgressInTitles,
        workflowLabels: { ...ticketTrackerDefaults.workflowLabels },
    };
}
async function loadInitDefaults(cwd) {
    try {
        return await (0, control_plane_config_1.loadConfig)(cwd);
    }
    catch {
        return discoverDefaults();
    }
}
function discoverDefaults() {
    return {
        branchPrefix: control_plane_config_1.DEFAULT_CONFIG.branchPrefix,
        approvals: {
            workflowStart: { ...control_plane_config_1.DEFAULT_CONFIG.approvals.workflowStart },
            requirementsSetup: { ...control_plane_config_1.DEFAULT_CONFIG.approvals.requirementsSetup },
        },
        dependencies: { ...control_plane_config_1.DEFAULT_CONFIG.dependencies },
        git: { ...control_plane_config_1.DEFAULT_CONFIG.git },
        workspaces: {
            ...control_plane_config_1.DEFAULT_CONFIG.workspaces,
            setupWatchPaths: control_plane_config_1.DEFAULT_CONFIG.workspaces.setupWatchPaths === "auto"
                ? "auto"
                : [...control_plane_config_1.DEFAULT_CONFIG.workspaces.setupWatchPaths],
        },
        workflowTemplateDefaults: (0, structured_clone_1.cloneStructured)(control_plane_config_1.DEFAULT_CONFIG.workflowTemplateDefaults),
        followup: { ...control_plane_config_1.DEFAULT_CONFIG.followup },
        aiWorkflowOptionAutofill: control_plane_config_1.DEFAULT_CONFIG.aiWorkflowOptionAutofill,
        foreignIssueApprovalScope: control_plane_config_1.DEFAULT_CONFIG.foreignIssueApprovalScope,
        issueCompletion: {
            target: control_plane_config_1.DEFAULT_CONFIG.issueCompletion.target,
            pullRequest: { ...control_plane_config_1.DEFAULT_CONFIG.issueCompletion.pullRequest },
        },
        paths: {
            issueNotes: control_plane_config_1.DEFAULT_CONFIG.paths.issueNotes,
            systemPrompts: { ...control_plane_config_1.DEFAULT_CONFIG.paths.systemPrompts },
        },
        i18n: { ...control_plane_config_1.DEFAULT_CONFIG.i18n },
        repositoryHost: {
            kind: control_plane_config_1.DEFAULT_CONFIG.repositoryHost.kind,
            projectRef: control_plane_config_1.DEFAULT_CONFIG.repositoryHost.projectRef,
            remoteName: control_plane_config_1.DEFAULT_CONFIG.repositoryHost.remoteName,
            baseBranch: control_plane_config_1.DEFAULT_CONFIG.repositoryHost.baseBranch,
            pullRequest: {
                defaultReviewers: [
                    ...control_plane_config_1.DEFAULT_CONFIG.repositoryHost.pullRequest.defaultReviewers,
                ],
            },
        },
        ticketTracker: {
            kind: control_plane_config_1.DEFAULT_CONFIG.ticketTracker.kind,
            projectRef: control_plane_config_1.DEFAULT_CONFIG.ticketTracker.projectRef,
            commentReactions: [...control_plane_config_1.DEFAULT_CONFIG.ticketTracker.commentReactions],
            showStepProgressInTitles: control_plane_config_1.DEFAULT_CONFIG.ticketTracker.showStepProgressInTitles,
            workflowLabels: { ...control_plane_config_1.DEFAULT_CONFIG.ticketTracker.workflowLabels },
        },
        customWorkers: { ...control_plane_config_1.DEFAULT_CONFIG.customWorkers },
        workers: {
            default: [...control_plane_config_1.DEFAULT_CONFIG.workers.default],
        },
        pollIntervalSec: control_plane_config_1.DEFAULT_CONFIG.pollIntervalSec,
        workerTimeoutSec: control_plane_config_1.DEFAULT_CONFIG.workerTimeoutSec,
        workerNoOutputTimeoutSec: control_plane_config_1.DEFAULT_CONFIG.workerNoOutputTimeoutSec,
        parallelism: {
            maxWorkers: control_plane_config_1.DEFAULT_CONFIG.parallelism.maxWorkers,
            maxIssues: control_plane_config_1.DEFAULT_CONFIG.parallelism.maxIssues,
            mode: control_plane_config_1.DEFAULT_CONFIG.parallelism.mode,
        },
        aiRunLimits: {
            maxRuns: control_plane_config_1.DEFAULT_CONFIG.aiRunLimits.maxRuns,
            maxHours: control_plane_config_1.DEFAULT_CONFIG.aiRunLimits.maxHours,
        },
        autoReviews: {
            plan: {
                maxRevisions: control_plane_config_1.DEFAULT_CONFIG.autoReviews.plan.maxRevisions,
            },
        },
        recurring: {
            maxActiveChildren: control_plane_config_1.DEFAULT_CONFIG.recurring.maxActiveChildren,
            updateChildTitleAfterPlan: control_plane_config_1.DEFAULT_CONFIG.recurring.updateChildTitleAfterPlan,
        },
        cooldownDefaultSecs: { ...control_plane_config_1.DEFAULT_CONFIG.cooldownDefaultSecs },
        eventHooks: [],
        maxNestedWorkflowDepth: control_plane_config_1.DEFAULT_CONFIG.maxNestedWorkflowDepth,
    };
}
async function resolveInitServiceKind(providedKind, input, locale, prompter) {
    if (providedKind) {
        if (!input.availableKinds.includes(providedKind)) {
            throw new provider_errors_1.UnsupportedProviderError(input.providerType, providedKind, locale);
        }
        return providedKind;
    }
    if (input.availableKinds.length === 0) {
        throw new Error((0, catalog_1.translate)(locale, "init.command.serviceKind.noneRegistered", {
            listLabel: input.listLabel,
        }));
    }
    if (input.availableKinds.length === 1) {
        const [onlyKind] = input.availableKinds;
        if (!onlyKind) {
            throw new Error((0, catalog_1.translate)(locale, "init.command.serviceKind.noneRegistered", {
                listLabel: input.listLabel,
            }));
        }
        console.log((0, catalog_1.translate)(locale, "prompts.command.using", {
            label: input.label.toLowerCase(),
            value: input.resolveDisplayName(onlyKind),
        }));
        return onlyKind;
    }
    return prompter.select({
        label: input.label,
        options: input.availableKinds.map((kind) => ({
            value: kind,
            label: input.resolveDisplayName(kind),
        })),
        defaultValue: input.availableKinds.includes(input.defaultValue)
            ? input.defaultValue
            : (input.availableKinds[0] ?? input.defaultValue),
    });
}
async function resolveRepositoryHostRemoteName(cwd, options, prompter) {
    const locale = await (0, locale_1.resolveInitLocale)(cwd, options);
    const label = (0, catalog_1.translate)(locale, "init.command.prompt.repositoryRemoteName");
    const remoteName = options.repositoryHostRemoteName ??
        (await resolveDiscoveredRemoteName(cwd, prompter, locale, label));
    validateRemoteName(locale, label, remoteName);
    return remoteName;
}
async function resolveDiscoveredRemoteName(cwd, prompter, locale, label) {
    const remoteNames = await (0, native_git_repository_client_1.discoverGitRemoteNames)(cwd);
    if (remoteNames.length === 1) {
        return remoteNames[0] ?? control_plane_config_1.DEFAULT_CONFIG.repositoryHost.remoteName;
    }
    if (remoteNames.length > 1) {
        if (!prompter.interactive) {
            throw new Error("Multiple git remotes found. Pass --remote-name <name>.");
        }
        return prompter.select({
            label,
            options: remoteNames.map((remoteName) => ({
                value: remoteName,
                label: remoteName,
            })),
            defaultValue: remoteNames.includes(control_plane_config_1.DEFAULT_CONFIG.repositoryHost.remoteName)
                ? control_plane_config_1.DEFAULT_CONFIG.repositoryHost.remoteName
                : (remoteNames[0] ?? control_plane_config_1.DEFAULT_CONFIG.repositoryHost.remoteName),
        });
    }
    return prompter.input({
        label,
        defaultValue: control_plane_config_1.DEFAULT_CONFIG.repositoryHost.remoteName,
        validate: (value) => validateRemoteName(locale, label, value),
    });
}
function validateRepositoryHostProjectRef(providerKind, projectRef) {
    (0, provider_resolution_1.resolveRepositoryHostProjectRef)({ kind: providerKind, projectRef });
}
function validateTicketTrackerProjectRef(providerKind, projectRef) {
    (0, provider_resolution_1.resolveTicketTrackerProjectRef)({ kind: providerKind, projectRef });
}
function validateNonEmpty(locale, label, value) {
    if (value.trim().length === 0) {
        throw new Error((0, catalog_1.translate)(locale, "init.command.validate.notEmpty", { label }));
    }
}
function validateRemoteName(locale, label, value) {
    validateNonEmpty(locale, label, value);
    if (!(0, remote_name_1.isValidRemoteName)(value)) {
        throw new Error((0, catalog_1.translate)(locale, "init.command.validate.invalidIdentifier", { label }));
    }
}
