import { basename } from "path";
import chalk from "chalk";
import compact from "lodash/compact";
import { move } from "../api/move";
import { shellQuote } from "../cli";
import { chooseDsns } from "../internal/chooseDsns";
import { getSchemaName } from "../internal/getSchemaName";
import { isTrueValue } from "../internal/isTrueValue";
import { log, print, stdlog } from "../internal/logging";
import { dsnFromToShort } from "../internal/names";
import { normalizeDsns } from "../internal/normalizeDsns";
import type { Args } from "../internal/parseArgs";
import {
  isInTmuxSession,
  runInTmux,
  tryReattachToTmuxSession,
} from "../internal/runInTmux";

/**
 * Moves a shard from one database to another with no downtime.
 */
export async function actionMove(args: Args): Promise<boolean> {
  await tryReattachToTmuxSession();

  const dsns = await normalizeDsns(args["dsns"]);

  let shard: number;
  if (args["shard"]?.match(/^(\d+)$/)) {
    shard = parseInt(args["shard"], 10);
  } else {
    throw "Please provide --shard, a microshard number to move";
  }

  const [fromDsns, fromWarnings] = chooseDsns({
    patterns: compact([args["from"]]),
    existingDsns: dsns,
    requireMatch: false,
  });
  if (fromDsns.length === 0) {
    throw "Please provide --from, source DB DSN, as postgresql://user:pass@host/db?options, or a DSN prefix";
  }

  const [toDsns, toWarnings] = chooseDsns({
    patterns: compact([args["to"]]),
    existingDsns: dsns,
    requireMatch: false,
  });
  if (toDsns.length === 0) {
    throw "Please provide --to, destination DB DSN, as postgresql://user:pass@host/db?options, or a DSN prefix";
  }

  const activateOnDestination = isTrueValue(args["activate-on-destination"]);
  if (activateOnDestination === undefined) {
    throw "Please provide --activate-on-destination=yes or --activate-on-destination=no";
  }

  const deactivateSQL = String(args["deactivate-sql"] || "") || undefined;

  const maxReplicationLagSec =
    Number(args["max-replication-lag-sec"] ?? "") || undefined;

  const wait = args["wait"];

  if (isInTmuxSession()) {
    const unpipe = stdlog.pipeToNewLogFile(`move-${shard}`);
    try {
      log(
        "$ " +
          [basename(process.argv[1]), ...process.argv.slice(2)]
            .map(shellQuote)
            .join(" "),
      );

      for (const warning of [...fromWarnings, ...toWarnings]) {
        print(warning);
      }

      const schema = await getSchemaName(fromDsns[0], shard);
      if (!schema) {
        throw `Can't determine schema name for microshard number ${shard}`;
      }

      await move({
        schema,
        fromDsn: fromDsns[0],
        toDsn: toDsns[0],
        commitAction: activateOnDestination
          ? "deactivate-activate"
          : "rename-to-new",
        deactivateSQL,
        maxReplicationLagSec,
        wait,
      });

      if (!activateOnDestination) {
        print(
          "\n" +
            chalk.yellow(
              "ATTENTION: the schema has been copied, but NOT activated on the destination. " +
                "So effectively, it was a dry-run, and the data still lives in the source DB. " +
                "To activate the schema on the destination and deactivate on the source, run " +
                "the tool with --activate-on-destination=yes option.",
            ),
        );
      }
    } finally {
      await unpipe();
    }
  } else {
    await runInTmux([
      [
        {
          key: shard.toString(),
          title: `microshard ${shard} | ${dsnFromToShort(fromDsns[0], toDsns[0])}`,
          command: process.argv,
        },
      ],
    ]);
  }

  return true;
}
