import chalk from "chalk";
import { Command, Option } from "commander";
import inquirer from "inquirer";
import { getUrlAndAdminKey } from "./lib/api";
import { readProjectConfig } from "./lib/config";
import { oneoffContext } from "./lib/context";
import { PushOptions, runPush } from "./lib/push";

export const deploy = new Command("deploy")
  .description(
    "Deploy your Convex functions to this project's production deployment"
  )
  .option("-v, --verbose", "Show full listing of changes")
  .option(
    "--dry-run",
    "Print out the generated configuration without deploying to your production deployment"
  )
  .addOption(
    new Option(
      "--typecheck <mode>",
      `Whether to check TypeScript files with \`tsc --noEmit\` before deploying.`
    )
      .choices(["enable", "try", "disable"])
      .default("try")
  )
  .addOption(
    new Option(
      "--codegen <mode>",
      "Whether to regenerate code in `convex/_generated/` before pushing."
    )
      .choices(["enable", "disable"])
      .default("enable")
  )
  .option("-y, --yes", "Skip confirmation prompt.")
  .addOption(new Option("--debug-bundle-path <path>").hideHelp())
  .addOption(new Option("--debug").hideHelp())
  // Hidden options to pass in admin key and url for tests and local development
  .addOption(new Option("--admin-key <adminKey>").hideHelp())
  .addOption(new Option("--url <url>").hideHelp())
  .action(async cmdOptions => {
    const ctx = oneoffContext;
    const projectConfig = (await readProjectConfig(ctx)).projectConfig;
    let adminKey = cmdOptions.adminKey;
    const url = cmdOptions.url ?? projectConfig.prodUrl;

    if (process.env.CONVEX_DEPLOY_KEY) {
      adminKey = process.env.CONVEX_DEPLOY_KEY;
    }

    const buildEnvironmentExpectsConvexDeployKey = process.env.VERCEL
      ? "Vercel"
      : process.env.NETLIFY
      ? "Netlify"
      : false;

    if (!adminKey) {
      if (buildEnvironmentExpectsConvexDeployKey) {
        console.error(
          chalk.yellow(
            `${buildEnvironmentExpectsConvexDeployKey} build environment detected but CONVEX_DEPLOY_KEY is not set. Set this environment variable to deploy from this environment.`
          )
        );
        ctx.fatalError(1);
      }
      adminKey = (
        await getUrlAndAdminKey(
          ctx,
          projectConfig.project,
          projectConfig.team,
          "prod"
        )
      ).adminKey;

      if (!cmdOptions.yes) {
        // Prompt for confirmation if we aren't using an env variable because
        // that means the developer is probably running this locally.
        const confirmed = (
          await inquirer.prompt([
            {
              type: "confirm",
              name: "confirmed",
              message:
                "About to deploy Convex functions to production. This will update `convex/_generated/clientConfig.js` to reference your production deployment.\n\nOkay to proceed?",
            },
          ])
        ).confirmed;

        if (!confirmed) {
          ctx.fatalError(1);
        }
      }
    }
    const options: PushOptions = {
      adminKey,
      verbose: !!cmdOptions.verbose,
      dryRun: !!cmdOptions.dryRun,
      typecheck: cmdOptions.typecheck,
      debug: !!cmdOptions.debug,
      debugBundlePath: cmdOptions.debugBundlePath,
      codegen: cmdOptions.codegen === "enable",
      deploymentType: "prod",
      url,
    };
    await runPush(oneoffContext, options);
    console.log(
      chalk.green(
        `${
          options.dryRun ? "Would have deployed" : "Deployed"
        } Convex functions to this project's production deployment successfully!`
      )
    );
  });
