import * as path from "path";
import { fileURLToPath } from "url";
import { promises as fs } from "fs";
import {
  Kysely,
  Migrator,
  MigrationResult,
  FileMigrationProvider,
  PostgresDialect,
  CamelCasePlugin,
} from "kysely";
import pkg from "pg";
const { Pool } = pkg;
import * as dotenv from "dotenv";

interface Database {}

export const migrate = async (arg: string) => {
  const __filename = fileURLToPath(import.meta.url);
  const __dirname = path.dirname(__filename);
  if (process.env.NODE_ENV !== "production") {
    dotenv.config({ path: path.join(__dirname, "../.env.local") });
  }
  const db = new Kysely<Database>({
    dialect: new PostgresDialect({
      pool: new Pool({
        host: process.env.DATABASE_HOST,
        database: process.env.DATABASE_NAME,
        port: parseInt(process.env.DATABASE_PORT!),
        user: process.env.DATABASE_USER,
        password: process.env.DATABASE_PASSWORD,
      }),
    }),
    plugins: [new CamelCasePlugin()],
  });
  const migrator = new Migrator({
    db,
    provider: new FileMigrationProvider({
      fs,
      path,
      migrationFolder: path.join(__dirname, "migrations"),
    }),
  });

  let error: any = null;
  let results: MigrationResult[] = [];

  if (arg === "up:all") {
    const out = await migrator.migrateToLatest();
    results = out.results ?? [];
    error = out.error;
  } else if (arg === "up:one") {
    const out = await migrator.migrateUp();
    results = out.results ?? [];
    error = out.error;
  } else if (arg === "down:all") {
    const migrations = await migrator.getMigrations();
    for (const _ of migrations) {
      const out = await migrator.migrateDown();
      if (out.results) {
        results = results.concat(out.results);
        error = out.error;
      }
    }
  } else if (arg === "down:one") {
    const out = await migrator.migrateDown();
    if (out.results) {
      results = out.results ?? [];
      error = out.error;
    }
  }

  results?.forEach((it) => {
    if (it.status === "Success") {
      console.log(
        `Migration "${it.migrationName} ${it.direction.toLowerCase()}" was executed successfully`,
      );
    } else if (it.status === "Error") {
      console.error(`Failed to execute migration "${it.migrationName}"`);
    }
  });

  if (error) {
    console.error("Failed to migrate");
    console.error(error);
    process.exit(1);
  }

  await db.destroy();
};

const arg = process.argv.slice(2).pop();
migrate(arg as string);
