import { Command, Option } from "commander";
import chalk from "chalk";
import { readProjectConfig } from "./lib/config";
import {
  ensureHasConvexDependency,
  formatSize,
  fatalServerErr,
} from "./lib/utils";
import axios, { AxiosResponse } from "axios";
import { version } from "../index.js";
import { getUrlAndAdminKey } from "./lib/api";
import { oneoffContext } from "./lib/context";

export const convexImport = new Command("import")
  .description("Import a file into a Convex table (EXPERIMENTAL)")
  .addOption(
    new Option(
      "--format <format>",
      "Input file format. CSV files must have a header, and each rows' entries are interpreted either as a (floating point) number or a string. JSON files must have a JSON object per line."
    )
      .choices(["csv", "json"])
      .default("csv")
  )
  .option(
    "--prod",
    "Import data into this project's production deployment. Defaults to your dev deployment without this flag."
  )
  .addOption(new Option("--url <url>").hideHelp())
  .addOption(new Option("--admin-key <adminKey>").hideHelp())
  .argument("<tableName>", "Destination table name (must be empty)")
  .argument("<path>", "Path to the input file")
  .action(async (tableName: string, path: string, options: any) => {
    const ctx = oneoffContext;
    const format = options.format;
    if (format !== "csv" && format !== "json") {
      throw new Error(`Invalid format; ${format}`);
    }
    const { projectConfig } = await readProjectConfig(ctx);
    const deploymentType = options.prod ? "prod" : "dev";
    let deploymentUrl, adminKey;
    if (!options.url || !options.adminKey) {
      let url;
      ({ url, adminKey } = await getUrlAndAdminKey(
        ctx,
        projectConfig.project,
        projectConfig.team,
        deploymentType
      ));
      deploymentUrl = url;
    }
    adminKey = options.adminKey ?? adminKey;
    deploymentUrl = options.url ?? deploymentUrl;
    await ensureHasConvexDependency(ctx, "import");

    if (!ctx.fs.exists(path)) {
      console.error(chalk.gray(`Error: Path ${path} does not exist.`));
      return await ctx.fatalError(1, "fs");
    }
    const data = ctx.fs.readUtf8File(path);
    console.log(
      chalk.yellow(
        `The \`npx convex import\` command is experimental and hasn't been fully polished yet.\nPlease report any issues on the Convex Community Discord (https://convex.dev/community).\n`
      )
    );
    console.log(
      chalk.gray(`Importing ${path} (${formatSize(data.length)})...`)
    );
    const urlName = encodeURIComponent(tableName);
    const urlFormat = encodeURIComponent(format);
    const client = axios.create();
    let resp: AxiosResponse;
    try {
      const url = `${deploymentUrl}/api/${version}/import?table_name=${urlName}&format=${urlFormat}`;
      resp = await client.post(url, data, {
        headers: {
          Authorization: `Convex ${adminKey}`,
          "Content-Type": "text/plain",
        },
      });
    } catch (e) {
      return await fatalServerErr(ctx, e);
    }
    console.log(
      chalk.green(`Wrote ${resp.data.numWritten} rows to ${tableName}.`)
    );
  });
