"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.addCompletionSpecCommand = exports.generateCompletionSpec = void 0;
const prettier_1 = __importDefault(require("prettier"));
const DEFAULT_FIG_SUBCOMMAND_NAME = "generate-fig-spec";
function convertDefaultValue(v) {
    if (typeof v === "string")
        return v;
    if (Array.isArray(v))
        return v.join(",");
    if (typeof v === "object")
        return undefined;
    return String(v);
}
function getTemplate(spec) {
    return __awaiter(this, void 0, void 0, function* () {
        return prettier_1.default.format(`
    // Autogenerated by @fig/complete-commander

    const completionSpec: Fig.Spec = ${JSON.stringify(spec)}

    export default completionSpec;
  `, { parser: "typescript" });
    });
}
function generateArg(_arg) {
    const { _name: name, description, required, variadic, defaultValue } = _arg;
    const arg = { name };
    if (description)
        arg.description = description;
    if (!required)
        arg.isOptional = true;
    if (variadic)
        arg.isVariadic = true;
    if (defaultValue)
        arg.default = convertDefaultValue(defaultValue);
    return arg;
}
function generateOption(_option) {
    const { short, long, flags, description, mandatory, required, optional, variadic, argChoices, defaultValue, } = _option;
    const name = new Set();
    if (short)
        name.add(short);
    if (long)
        name.add(long);
    const option = { name: Array.from(name) };
    if (description)
        option.description = description;
    if (mandatory)
        option.isRequired = true;
    // Option argument e.g. "-f, --flag <string>"
    // If required and optional are both false it does not have an argument
    if (required || optional) {
        // eslint-disable-next-line no-useless-escape
        const matches = flags.match(/.*[\[<](.*)[\]>]/); // !!! This is all but an useless escape. It is required to make the regex working
        const arg = {
            name: matches ? matches[1].replace(/\./g, "") : "",
        };
        if (optional)
            arg.isOptional = true;
        if (variadic)
            arg.isVariadic = true;
        if (argChoices)
            arg.suggestions = argChoices;
        if (defaultValue)
            arg.default = convertDefaultValue(defaultValue);
        option.args = arg;
    }
    return option;
}
function helpSubcommand({ _helpCommandName, // 'help'
_helpCommandDescription, _helpCommandnameAndArgs, // 'help [cmd]'
 }) {
    const [, arg] = _helpCommandnameAndArgs.split(" ");
    return Object.assign({ name: _helpCommandName, description: _helpCommandDescription, priority: 49 }, (arg && {
        args: {
            name: arg.slice(1, -1),
            isOptional: true,
            template: "help",
        },
    }));
}
function helpOption({ _helpDescription, _helpShortFlag, _helpLongFlag, }) {
    return {
        name: [_helpShortFlag, _helpLongFlag],
        description: _helpDescription,
        priority: 49,
    };
}
function generateCommand(_command, figSpecCommandName) {
    const { _name, _description, _aliases, commands, _args, options, _addImplicitHelpCommandL, _hasHelpOption, _hidden, } = _command;
    if (_name === figSpecCommandName)
        return undefined;
    const name = _aliases.length > 0 ? Array.from(new Set([_name, ..._aliases])) : _name;
    const command = { name };
    if (_description)
        command.description = _description;
    if (_hidden)
        command.hidden = true;
    // Subcommands
    if (commands.length) {
        command.subcommands = [];
        for (const cmd of commands) {
            const subcommand = generateCommand(cmd, figSpecCommandName);
            if (subcommand)
                command.subcommands.push(subcommand);
        }
        if (_addImplicitHelpCommandL !== false) {
            command.subcommands.push(helpSubcommand(_command));
        }
    }
    // Options
    command.options = [];
    if (options.length) {
        command.options = options.map(generateOption);
    }
    if (_hasHelpOption) {
        command.options.push(helpOption(_command));
    }
    // Args
    if (_args.length) {
        command.args = _args.map(generateArg);
    }
    return command;
}
function generateCompletionSpec(command, options) {
    return __awaiter(this, void 0, void 0, function* () {
        const figSpecCommandName = (options === null || options === void 0 ? void 0 : options.figSpecCommandName) || DEFAULT_FIG_SUBCOMMAND_NAME;
        // The first subcommand will never have the name of the `figSpecCommandName`
        // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
        const spec = getTemplate(generateCommand(command, figSpecCommandName));
        return spec;
    });
}
exports.generateCompletionSpec = generateCompletionSpec;
function addCompletionSpecCommand(command) {
    command
        .command(DEFAULT_FIG_SUBCOMMAND_NAME)
        .description("Print the Fig completion spec")
        .action(() => __awaiter(this, void 0, void 0, function* () {
        const spec = yield generateCompletionSpec(command);
        console.log(spec);
    }));
}
exports.addCompletionSpecCommand = addCompletionSpecCommand;
