"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
  for (var name in all)
    __defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
  if (from && typeof from === "object" || typeof from === "function") {
    for (let key of __getOwnPropNames(from))
      if (!__hasOwnProp.call(to, key) && key !== except)
        __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  }
  return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
  // If the importer is in node compatibility mode or this is not an ESM
  // file that has been converted to a CommonJS file using a Babel-
  // compatible transform (i.e. "__esModule" has not been set), then set
  // "default" to the CommonJS "module.exports" for node compatibility.
  isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
  mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var init_command_exports = {};
__export(init_command_exports, {
  InitCommand: () => InitCommand
});
module.exports = __toCommonJS(init_command_exports);
var import_chalk = __toESM(require("chalk"));
var fs = __toESM(require("fs"));
var pathlib = __toESM(require("path"));
var errors = __toESM(require("../errors"));
var import_project_templates = require("../project-templates");
var utils = __toESM(require("../utils"));
var import_global_command = require("./global-command");
const projectTypes = ["bot", "integration", "plugin"];
class InitCommand extends import_global_command.GlobalCommand {
  async run() {
    const projectType = await this._promptProjectType();
    const workDir = utils.path.absoluteFrom(utils.path.cwd(), this.argv.workDir);
    try {
      if (projectType === "bot") {
        await this._initBot({ workDir });
        return;
      }
      if (projectType === "integration") {
        const workspaceHandle = await this._promptWorkspaceHandle();
        await this._initIntegration({ workDir, workspaceHandle });
        return;
      }
      if (projectType === "plugin") {
        const workspaceHandle = await this._promptWorkspaceHandle();
        await this._initPlugin({ workDir, workspaceHandle });
        return;
      }
    } catch (error) {
      if (error instanceof errors.AbortedOperationError) {
        this.logger.log(error.message);
        return;
      }
      throw error;
    }
    throw new errors.BotpressCLIError(`Unknown project type: ${projectType}`);
  }
  async _promptWorkspaceHandle() {
    const client = await this.getAuthenticatedClient({}) ?? void 0;
    const nameParts = this.argv.name?.split("/", 2) ?? [];
    const workspaceHandle = nameParts.length > 1 ? nameParts[0] : void 0;
    const resolver = await WorkspaceResolver.from({
      client,
      workspaceHandle,
      prompt: this.prompt,
      logger: this.logger
    });
    return await resolver.getWorkspaceHandle();
  }
  async _promptProjectType() {
    if (this.argv.type) {
      return this.argv.type;
    }
    const promptedType = await this.prompt.select("What type of project do you wish to initialize?", {
      choices: projectTypes.map((t) => ({ title: t, value: t }))
    });
    if (!promptedType) {
      throw new errors.ParamRequiredError("Project Type");
    }
    return promptedType;
  }
  _initPlugin = async (args) => {
    const { workDir, workspaceHandle } = args;
    const template = await this._getOrPromptForTemplate("plugin");
    const name = await this._getName("plugin", template.defaultProjectName);
    const { fullName, shortName } = this._getFullNameAndShortName({ workspaceHandle, name });
    await this._copy({
      srcDir: template.absolutePath,
      destDir: workDir,
      name: shortName,
      pkgJson: {
        pluginName: fullName
      }
    });
    this.logger.success(`Plugin project initialized in ${import_chalk.default.bold(pathlib.join(workDir, shortName))}`);
  };
  async _getOrPromptForTemplate(type) {
    const availableTemplates = import_project_templates.ProjectTemplates.templates[type];
    if (this.argv.template) {
      const template = availableTemplates.find((t) => t.identifier === this.argv.template);
      if (!template) {
        throw new errors.BotpressCLIError(`No ${type} template found for identifier "${this.argv.template}"`);
      }
      return template;
    }
    if (availableTemplates.length === 1) {
      this.logger.log(`Using default template: ${import_chalk.default.bold(availableTemplates[0].fullName)}`);
      return availableTemplates[0];
    }
    return await this._promptForTemplate(availableTemplates);
  }
  async _promptForTemplate(availableTemplates) {
    const templateIndex = await this.prompt.select("Which template do you want to use?", {
      choices: availableTemplates.map((template, index) => ({
        title: template.fullName,
        value: index
      })),
      default: 0
    });
    if (templateIndex === void 0 || templateIndex < 0 || templateIndex >= availableTemplates.length) {
      this.logger.log(`Using default template: ${import_chalk.default.bold(availableTemplates[0].fullName)}`);
      return availableTemplates[0];
    }
    return availableTemplates[templateIndex];
  }
  _getFullNameAndShortName(args) {
    const [workspaceOrName, projectName] = args.name.split("/", 2);
    const shortName = projectName ?? workspaceOrName;
    const fullName = `${args.workspaceHandle}/${shortName}`;
    return { shortName, fullName };
  }
  _initBot = async (args) => {
    const { workDir } = args;
    const template = await this._getOrPromptForTemplate("bot");
    const name = await this._getName("bot", template.defaultProjectName);
    await this._copy({ srcDir: template.absolutePath, destDir: workDir, name, pkgJson: {} });
    this.logger.success(`Bot project initialized in ${import_chalk.default.bold(pathlib.join(workDir, name))}`);
  };
  _initIntegration = async (args) => {
    const { workDir, workspaceHandle } = args;
    const template = await this._getOrPromptForTemplate("integration");
    const name = await this._getName("integration", template.defaultProjectName);
    const { fullName, shortName } = this._getFullNameAndShortName({ workspaceHandle, name });
    await this._copy({
      srcDir: template.absolutePath,
      destDir: workDir,
      name: shortName,
      pkgJson: {
        integrationName: fullName
      }
    });
    this.logger.success(`Integration project initialized in ${import_chalk.default.bold(pathlib.join(workDir, shortName))}`);
    return;
  };
  _getName = async (projectType, defaultName) => {
    if (this.argv.name) {
      return this.argv.name;
    }
    const promptMessage = `What is the name of your ${projectType}?`;
    const promptedName = await this.prompt.text(promptMessage, { initial: defaultName });
    if (!promptedName) {
      throw new errors.ParamRequiredError("Project Name");
    }
    return promptedName;
  };
  _copy = async (props) => {
    const { srcDir, destDir, name, pkgJson } = props;
    const dirName = utils.casing.to.kebabCase(name);
    const destination = pathlib.join(destDir, dirName);
    const destinationCanBeUsed = await this._checkIfDestinationCanBeUsed(destination);
    if (!destinationCanBeUsed) {
      throw new errors.AbortedOperationError();
    }
    await fs.promises.rm(destination, { recursive: true, force: true });
    await fs.promises.cp(srcDir, destination, { recursive: true });
    const json = await utils.pkgJson.readPackageJson(destination).catch((thrown) => {
      throw errors.BotpressCLIError.wrap(thrown, "Failed to read package.json file");
    });
    const pkgJsonName = utils.casing.to.snakeCase(name);
    const updatedJson = { name: pkgJsonName, ...json, ...pkgJson };
    await utils.pkgJson.writePackageJson(destination, updatedJson).catch((thrown) => {
      throw errors.BotpressCLIError.wrap(thrown, "Failed to write package.json file");
    });
  };
  _checkIfDestinationCanBeUsed = async (destination) => {
    if (fs.existsSync(destination)) {
      const override = await this.prompt.confirm(
        `Directory ${import_chalk.default.bold(destination)} already exists. Do you want to overwrite it?`
      );
      if (!override) {
        return false;
      }
    }
    return true;
  };
}
class WorkspaceResolver {
  constructor(_client, _workspaceHandle, _prompt, _logger) {
    this._client = _client;
    this._workspaceHandle = _workspaceHandle;
    this._prompt = _prompt;
    this._logger = _logger;
  }
  _workspaces = [];
  _currentWorkspace;
  static async from({
    client,
    workspaceHandle,
    prompt,
    logger
  }) {
    const resolver = new WorkspaceResolver(client, workspaceHandle, prompt, logger);
    await resolver._fetchWorkspaces();
    return resolver;
  }
  async getWorkspaceHandle() {
    if (this._hasNoWorkspaces()) {
      return this._promptForArbitraryWorkspaceHandle();
    }
    const workspace = await this._promptUserToSelectWorkspace();
    return workspace.handle || await this._assignHandleToWorkspace(workspace);
  }
  async _fetchWorkspaces() {
    if (!this._isAuthenticated()) {
      return;
    }
    const workspaces = await this._getClient().client.list.workspaces({}).collect({}).catch((thrown) => {
      throw errors.BotpressCLIError.wrap(thrown, "Unable to list your workspaces");
    });
    const currentWorkspace = workspaces.find((ws) => ws.id === this._getClient().workspaceId);
    this._workspaces = workspaces;
    this._currentWorkspace = currentWorkspace;
  }
  _isAuthenticated() {
    return !!this._client;
  }
  _hasNoWorkspaces() {
    return !this._isAuthenticated() || this._workspaces.length === 0 || !this._currentWorkspace;
  }
  async _promptForArbitraryWorkspaceHandle() {
    if (this._workspaceHandle) {
      return this._workspaceHandle;
    }
    const handle = await this._prompt.text("Enter your workspace handle");
    if (!handle) {
      throw new errors.ParamRequiredError("Workspace handle");
    }
    return handle;
  }
  async _promptUserToSelectWorkspace() {
    const workspaceChoices = this._workspaces.map((ws) => ({
      title: ws.name,
      value: ws.id
    }));
    const initialChoice = {
      title: this._currentWorkspace.name,
      value: this._currentWorkspace.id
    };
    const workspaceId = await this._prompt.select("Which workspace do you want to use?", {
      initial: initialChoice,
      choices: workspaceChoices
    });
    if (!workspaceId) {
      throw new errors.ParamRequiredError("Workspace");
    }
    return this._workspaces.find((ws) => ws.id === workspaceId);
  }
  async _assignHandleToWorkspace(workspace) {
    this._logger.warn("It seems you don't have a workspace handle yet.");
    let claimedHandle;
    do {
      const desiredHandle = await this._promptForDesiredHandle();
      const isAvailable = await this._checkHandleAvailability(desiredHandle);
      if (isAvailable) {
        claimedHandle = desiredHandle;
        await this._updateWorkspaceWithHandle(workspace.id, claimedHandle);
      }
    } while (!claimedHandle);
    this._logger.success(`Handle "${claimedHandle}" is yours!`);
    return claimedHandle;
  }
  async _promptForDesiredHandle() {
    const desiredHandle = await this._prompt.text("Please enter a workspace handle");
    if (!desiredHandle) {
      throw new errors.BotpressCLIError("Workspace handle is required");
    }
    return desiredHandle;
  }
  async _checkHandleAvailability(handle) {
    const { available, suggestions } = await this._getClient().client.checkHandleAvailability({ handle });
    if (!available) {
      this._logger.warn(`Handle "${handle}" is not available. Suggestions: ${suggestions.join(", ")}`);
      return false;
    }
    return true;
  }
  async _updateWorkspaceWithHandle(workspaceId, handle) {
    try {
      await this._getClient().switchWorkspace(workspaceId).updateWorkspace({ handle });
    } catch (thrown) {
      throw errors.BotpressCLIError.wrap(thrown, `Could not claim handle "${handle}"`);
    }
  }
  _getClient() {
    if (!this._client) {
      throw new errors.BotpressCLIError("Could not authenticate");
    }
    return this._client;
  }
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
  InitCommand
});
//# sourceMappingURL=init-command.js.map
