import { sql } from "drizzle-orm";
import fs from "fs";
import path from "path";

import { logger } from "@turbostarter/shared/logger";

import { db } from "../server";

interface JournalEntry {
  idx: number;
  version: string;
  when: number;
  tag: string;
  breakpoints: boolean;
}

interface JournalFile {
  version: string;
  dialect: string;
  entries?: JournalEntry[];
}

const JOURNAL_PATH = path.resolve("migrations/meta/_journal.json");

function loadJournalEntries(): JournalEntry[] {
  if (!fs.existsSync(JOURNAL_PATH)) {
    throw new Error(`Migrations journal not found at ${JOURNAL_PATH}`);
  }

  const journalFile = fs.readFileSync(JOURNAL_PATH, "utf-8");
  const parsed = JSON.parse(journalFile) as JournalFile;

  return [...(parsed.entries ?? [])].sort((a, b) => a.idx - b.idx);
}

function toTimestamp(value: unknown): number | null {
  if (typeof value === "number") {
    return value;
  }

  if (typeof value === "string") {
    const parsed = Number(value);
    return Number.isNaN(parsed) ? null : parsed;
  }

  if (typeof value === "bigint") {
    return Number(value);
  }

  if (value instanceof Date) {
    return value.getTime();
  }

  return null;
}

async function fetchAppliedMigrationTimestamps(): Promise<number[]> {
  const result = await db.execute(
    sql`SELECT created_at FROM "drizzle"."__drizzle_migrations" ORDER BY created_at`,
  );

  return Array.from(result)
    .map((row) => toTimestamp((row as { created_at?: unknown }).created_at))
    .filter((timestamp): timestamp is number => timestamp !== null);
}

async function main() {
  const journalEntries = loadJournalEntries();
  const appliedTimestamps = await fetchAppliedMigrationTimestamps();
  const appliedTimestampSet = new Set(appliedTimestamps);

  const appliedMigrations = journalEntries.filter((entry) =>
    appliedTimestampSet.has(entry.when),
  );
  const pendingMigrations = journalEntries.filter(
    (entry) => !appliedTimestampSet.has(entry.when),
  );

  logger.info("\nApplied migrations:");
  if (appliedMigrations.length === 0) {
    logger.info("(none)");
  } else {
    appliedMigrations.forEach((entry) => logger.info(`- ${entry.tag}`));
  }

  logger.info("\nPending migrations:");
  if (pendingMigrations.length === 0) {
    logger.info("(none)");
  } else {
    pendingMigrations.forEach((entry) => logger.info(`- ${entry.tag}`));
  }
}

void main()
  .catch((err) => {
    logger.error(err);
    process.exit(1);
  })
  .then(() => {
    process.exit(0);
  });
