"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseEventHookArgs = parseEventHookArgs;
const catalog_1 = require("../../i18n/catalog");
const shared_1 = require("./shared");
const PATHLESS_CREATE_RUNNERS = new Set(["worker", "node", "python3", "bash"]);
function parseEventHookArgs(args, locale = catalog_1.DEFAULT_APP_LOCALE) {
    const [action, ...rest] = args;
    switch (action) {
        case "add":
            return parseEventHookAddArgs(rest, locale);
        case "list":
            return parseEventHookListArgs(rest, locale);
        case "remove":
            return parseEventHookRemoveArgs(rest, locale);
        case "test":
            return parseEventHookTestArgs(rest, locale);
        case "config":
            return parseEventHookConfigArgs(rest, locale);
        case "create":
            return parseEventHookCreateArgs(rest, locale);
        case "update":
            return parseEventHookUpdateArgs(rest, locale);
        default:
            throw new Error((0, catalog_1.translate)(locale, "cli.parser.eventHook.usage"));
    }
}
function parseEventHookConfigArgs(args, locale) {
    const [command, ...rest] = args;
    switch (command) {
        case "show":
            if (rest.length > 0) {
                throwUnknownOption(rest[0], locale);
            }
            return { action: "config", command: "show" };
        case "set": {
            let userDir;
            for (let index = 0; index < rest.length; index += 1) {
                const token = rest[index];
                const value = rest[index + 1];
                switch (token) {
                    case "--user-dir":
                        userDir = parseRequiredStringOption(token, value, locale);
                        index += 1;
                        break;
                    default:
                        throwUnknownOption(token, locale);
                }
            }
            if (userDir === undefined) {
                throw new Error((0, catalog_1.translate)(locale, "cli.parser.eventHook.userDirRequired"));
            }
            return { action: "config", command: "set", userDir };
        }
        default:
            throw new Error((0, catalog_1.translate)(locale, "cli.parser.eventHook.configUsage"));
    }
}
function parseEventHookAddArgs(args, locale) {
    let scope;
    let hookPath;
    let runner;
    let cwd;
    const on = [];
    let allRepos = false;
    for (let index = 0; index < args.length; index += 1) {
        const token = args[index];
        const value = args[index + 1];
        switch (token) {
            case "--scope":
                scope = assignScope(scope, (0, shared_1.parseRequiredOptionValue)(token, value, locale, (option) => parseEventHookScope(option, locale)), locale);
                index += 1;
                break;
            case "--cwd":
                cwd = assignCwd(cwd, parseCwdOption(token, value, locale), locale);
                index += 1;
                break;
            case "--all-repos":
                allRepos = true;
                break;
            case "--path":
                hookPath = parseRequiredStringOption(token, value, locale);
                index += 1;
                break;
            case "--runner":
                runner = parseRequiredStringOption(token, value, locale);
                index += 1;
                break;
            case "--on":
                on.push(parseRequiredStringOption(token, value, locale));
                index += 1;
                break;
            default:
                throwUnknownOption(token, locale);
        }
    }
    const requiredScope = requireScope(scope, locale);
    validateTargetOptions({ action: "add", scope: requiredScope, cwd, allRepos }, locale);
    return {
        action: "add",
        scope: requiredScope,
        ...(cwd !== undefined ? { cwd } : {}),
        allRepos,
        path: requirePath(hookPath, locale),
        ...(runner !== undefined ? { runner } : {}),
        on,
    };
}
function parseEventHookListArgs(args, locale) {
    let scope;
    let cwd;
    let allRepos = false;
    for (let index = 0; index < args.length; index += 1) {
        const token = args[index];
        const value = args[index + 1];
        switch (token) {
            case "--scope":
                scope = assignListScope(scope, (0, shared_1.parseRequiredOptionValue)(token, value, locale, (option) => parseEventHookListScope(option, locale)), locale);
                index += 1;
                break;
            case "--cwd":
                cwd = assignCwd(cwd, parseCwdOption(token, value, locale), locale);
                index += 1;
                break;
            case "--all-repos":
                allRepos = true;
                break;
            default:
                throwUnknownOption(token, locale);
        }
    }
    const resolvedScope = scope ?? "all";
    validateTargetOptions({ action: "list", scope: resolvedScope, cwd, allRepos }, locale);
    return {
        action: "list",
        scope: resolvedScope,
        ...(cwd !== undefined ? { cwd } : {}),
        allRepos,
    };
}
function parseEventHookRemoveArgs(args, locale) {
    let scope;
    let hookPath;
    let cwd;
    let allRepos = false;
    for (let index = 0; index < args.length; index += 1) {
        const token = args[index];
        const value = args[index + 1];
        switch (token) {
            case "--scope":
                scope = assignScope(scope, (0, shared_1.parseRequiredOptionValue)(token, value, locale, (option) => parseEventHookScope(option, locale)), locale);
                index += 1;
                break;
            case "--cwd":
                cwd = assignCwd(cwd, parseCwdOption(token, value, locale), locale);
                index += 1;
                break;
            case "--all-repos":
                allRepos = true;
                break;
            case "--path":
                hookPath = parseRequiredStringOption(token, value, locale);
                index += 1;
                break;
            default:
                throwUnknownOption(token, locale);
        }
    }
    const requiredScope = requireScope(scope, locale);
    validateTargetOptions({ action: "remove", scope: requiredScope, cwd, allRepos }, locale);
    return {
        action: "remove",
        scope: requiredScope,
        ...(cwd !== undefined ? { cwd } : {}),
        allRepos,
        path: requirePath(hookPath, locale),
    };
}
function parseEventHookTestArgs(args, locale) {
    let scope;
    let hookPath;
    let runner;
    for (let index = 0; index < args.length; index += 1) {
        const token = args[index];
        const value = args[index + 1];
        switch (token) {
            case "--scope":
                scope = assignScope(scope, (0, shared_1.parseRequiredOptionValue)(token, value, locale, (option) => parseEventHookScope(option, locale)), locale);
                index += 1;
                break;
            case "--path":
                hookPath = parseRequiredStringOption(token, value, locale);
                index += 1;
                break;
            case "--runner":
                runner = parseRequiredStringOption(token, value, locale);
                index += 1;
                break;
            default:
                throwUnknownOption(token, locale);
        }
    }
    return {
        action: "test",
        ...(scope !== undefined ? { scope } : {}),
        path: requirePath(hookPath, locale),
        ...(runner !== undefined ? { runner } : {}),
    };
}
function parseEventHookCreateArgs(args, locale) {
    const parsed = parseEventHookAuthoringOptions(args, locale, {
        action: "create",
        allowPathOmission: true,
        allowRunner: true,
        allowTriggers: true,
    });
    if (parsed.draftPath !== undefined) {
        return {
            action: "create",
            mode: "apply-draft",
            draftPath: parsed.draftPath,
        };
    }
    if (parsed.on.length === 0) {
        throw new Error((0, catalog_1.translate)(locale, "cli.parser.eventHook.onRequired"));
    }
    if (parsed.path === undefined &&
        parsed.runner !== undefined &&
        !PATHLESS_CREATE_RUNNERS.has(parsed.runner)) {
        throw new Error((0, catalog_1.translate)(locale, "cli.parser.eventHook.customRunnerPathRequired"));
    }
    return {
        action: "create",
        mode: "prompt",
        scope: parsed.scope,
        ...(parsed.cwd !== undefined ? { cwd: parsed.cwd } : {}),
        allRepos: parsed.allRepos,
        ...(parsed.path !== undefined ? { path: parsed.path } : {}),
        ...(parsed.runner !== undefined ? { runner: parsed.runner } : {}),
        on: parsed.on,
        prompt: parsed.prompt,
        saveDraft: parsed.saveDraft,
    };
}
function parseEventHookUpdateArgs(args, locale) {
    const parsed = parseEventHookAuthoringOptions(args, locale, {
        action: "update",
        allowPathOmission: false,
        allowRunner: false,
        allowTriggers: false,
    });
    if (parsed.draftPath !== undefined) {
        return {
            action: "update",
            mode: "apply-draft",
            draftPath: parsed.draftPath,
        };
    }
    return {
        action: "update",
        mode: "prompt",
        scope: parsed.scope,
        ...(parsed.cwd !== undefined ? { cwd: parsed.cwd } : {}),
        allRepos: parsed.allRepos,
        path: requirePath(parsed.path, locale),
        prompt: parsed.prompt,
        saveDraft: parsed.saveDraft,
    };
}
function parseEventHookAuthoringOptions(args, locale, options) {
    let scope;
    let hookPath;
    let runner;
    let prompt;
    let draftPath;
    let cwd;
    const on = [];
    let allRepos = false;
    let saveDraft = false;
    for (let index = 0; index < args.length; index += 1) {
        const token = args[index];
        const value = args[index + 1];
        switch (token) {
            case "--scope":
                scope = assignScope(scope, (0, shared_1.parseRequiredOptionValue)(token, value, locale, (option) => parseEventHookScope(option, locale)), locale);
                index += 1;
                break;
            case "--cwd":
                cwd = assignCwd(cwd, parseCwdOption(token, value, locale), locale);
                index += 1;
                break;
            case "--all-repos":
                allRepos = true;
                break;
            case "--path":
                hookPath = parseRequiredStringOption(token, value, locale);
                index += 1;
                break;
            case "--runner":
                if (!options.allowRunner) {
                    throwUnknownOption(token, locale);
                }
                runner = parseRequiredStringOption(token, value, locale);
                index += 1;
                break;
            case "--on":
                if (!options.allowTriggers) {
                    throwUnknownOption(token, locale);
                }
                on.push(parseRequiredStringOption(token, value, locale));
                index += 1;
                break;
            case "--prompt":
                prompt = parseRequiredFreeformTextOption(token, value, locale);
                index += 1;
                break;
            case "--save-draft":
                saveDraft = true;
                break;
            case "--apply-draft":
                draftPath = parseRequiredStringOption(token, value, locale);
                index += 1;
                break;
            default:
                throwUnknownOption(token, locale);
        }
    }
    if (draftPath !== undefined) {
        ensureApplyDraftOnly({ scope, cwd, allRepos, path: hookPath, runner, on, prompt, saveDraft }, locale);
        return {
            scope: "repo",
            allRepos: false,
            on: [],
            prompt: "",
            saveDraft: false,
            draftPath,
        };
    }
    const requiredScope = requireScope(scope, locale);
    validateTargetOptions({ action: options.action, scope: requiredScope, cwd, allRepos }, locale);
    return {
        scope: requiredScope,
        ...(cwd !== undefined ? { cwd } : {}),
        allRepos,
        ...(hookPath !== undefined ? { path: hookPath } : {}),
        ...(runner !== undefined ? { runner } : {}),
        on,
        prompt: requirePrompt(prompt, locale),
        saveDraft,
    };
}
function parseEventHookScope(value, locale) {
    if (value === "repo" || value === "user") {
        return value;
    }
    throw new Error((0, catalog_1.translate)(locale, "cli.parser.eventHook.invalidScope", { value }));
}
function parseEventHookListScope(value, locale) {
    if (value === "all") {
        return value;
    }
    return parseEventHookScope(value, locale);
}
function parseCwdOption(token, value, locale) {
    return parseRequiredStringOption(token, value, locale);
}
function parseRequiredStringOption(token, value, locale) {
    return (0, shared_1.parseRequiredOptionValue)(token, value, locale, (option) => (0, shared_1.parseNonEmptyStringArg)(token, option, locale));
}
function parseRequiredFreeformTextOption(token, value, locale) {
    return (0, shared_1.parseRequiredOptionValue)(token, value, locale, (option) => (0, shared_1.parseNonEmptyFreeformTextArg)(token, option, locale));
}
function assignScope(current, next, locale) {
    if (current !== undefined) {
        throw new Error((0, catalog_1.translate)(locale, "cli.parser.eventHook.scopeError"));
    }
    return next;
}
function assignListScope(current, next, locale) {
    if (current !== undefined) {
        throw new Error((0, catalog_1.translate)(locale, "cli.parser.eventHook.scopeError"));
    }
    return next;
}
function assignCwd(current, next, locale) {
    if (current !== undefined) {
        throw new Error((0, catalog_1.translate)(locale, "cli.parser.eventHook.multipleCwdError"));
    }
    return next;
}
function requireScope(scope, locale) {
    if (scope === undefined) {
        throw new Error((0, catalog_1.translate)(locale, "cli.parser.eventHook.scopeRequired"));
    }
    return scope;
}
function validateTargetOptions(input, locale) {
    if (input.allRepos && input.cwd !== undefined) {
        throw new Error((0, catalog_1.translate)(locale, "cli.parser.eventHook.allReposWithCwd"));
    }
    if (input.scope === "repo" && input.allRepos) {
        throw new Error((0, catalog_1.translate)(locale, "cli.parser.eventHook.repoAllReposError"));
    }
}
function requirePath(pathValue, locale) {
    if (pathValue === undefined) {
        throw new Error((0, catalog_1.translate)(locale, "cli.parser.eventHook.pathRequired"));
    }
    return pathValue;
}
function requirePrompt(prompt, locale) {
    if (prompt === undefined) {
        throw new Error((0, catalog_1.translate)(locale, "cli.parser.eventHook.promptRequired"));
    }
    return prompt;
}
function ensureApplyDraftOnly(input, locale) {
    if (input.scope !== undefined ||
        input.cwd !== undefined ||
        input.allRepos ||
        input.path !== undefined ||
        input.runner !== undefined ||
        input.on.length > 0 ||
        input.prompt !== undefined ||
        input.saveDraft) {
        throw new Error((0, catalog_1.translate)(locale, "cli.parser.eventHook.applyDraftOnly"));
    }
}
function throwUnknownOption(token, locale) {
    throw new Error((0, catalog_1.translate)(locale, "cli.parser.eventHook.unknownOption", {
        token: token ?? "",
    }));
}
