/* eslint-disable no-console */
import fs from 'fs';
import path from 'path';

import { createClient, ClickHouseClient } from '@clickhouse/client';
import { config } from 'dotenv';

config({
  path: process.env.NODE_ENV === 'test' ? '.env.test' : '.env',
  override: true,
});

const clickhouseUrl = () => {
  const url = process.env.CLICKHOUSE_URL;

  if (url) return url;

  throw new Error(
    'CLICKHOUSE_URL environment variable is not set. Please set it to the ClickHouse URL.',
  );
};

async function ensureDatabaseExists() {
  const [url, database] = clickhouseUrl().split(/\/(?=[^/]*$)/);
  const client = createClient({
    url,
  });

  await client.command({
    query: `CREATE DATABASE IF NOT EXISTS "${database}"`,
  });
  await client.command({
    query: `SET enable_json_type = 1`,
  });

  await client.close();
}

async function ensureMigrationTable(client: ClickHouseClient) {
  await client.command({
    query: `
        CREATE TABLE IF NOT EXISTS migrations (
          filename String,
          applied_at DateTime DEFAULT now()
        ) ENGINE = MergeTree()
      ORDER BY filename;
    `,
  });
}

async function hasMigrationBeenRun(
  filename: string,
  client: ClickHouseClient,
): Promise<boolean> {
  const resultSet = await client.query({
    query: `SELECT count() as count FROM migrations WHERE filename = {filename:String}`,
    query_params: { filename },
    format: 'JSON',
  });
  const result = await resultSet.json<{ count: number }>();

  return result.data[0].count > 0;
}

async function recordMigration(filename: string, client: ClickHouseClient) {
  await client.insert({
    table: 'migrations',
    values: [{ filename }],
    format: 'JSONEachRow',
  });
}

async function runMigrations() {
  const dir = path.join(__dirname);
  const files = fs.readdirSync(dir).filter((f) => f.endsWith('.sql'));

  await ensureDatabaseExists();

  const client = createClient({
    url: clickhouseUrl(),
  });

  await ensureMigrationTable(client);

  for (const file of files) {
    const alreadyRun = await hasMigrationBeenRun(file, client);

    if (alreadyRun) {
      console.log(`✔︎ Skipping already applied migration: ${file}`);
      continue;
    }

    const sql = fs.readFileSync(path.join(dir, file), 'utf8');

    console.log(`⚡ Running ${file}...`);
    await client.command({ query: sql });
    await recordMigration(file, client);
  }

  console.log('✅ All migrations applied.');
  await client.close();
}

runMigrations().catch((err) => {
  console.error('Migration error:', err);
  process.exit(1);
});
