#!/usr/bin/env node
import { execFileSync } from 'node:child_process';
import { existsSync, readFileSync } from 'node:fs';
import { dirname, resolve } from 'node:path';
import { fileURLToPath } from 'node:url';
import pg from 'pg';

const projectDir = resolve(dirname(fileURLToPath(import.meta.url)), '..');
const envPath = resolve(projectDir, '.env');

if (existsSync(envPath)) {
  for (const line of readFileSync(envPath, 'utf8').split('\n')) {
    const trimmed = line.trim();
    if (!trimmed || trimmed.startsWith('#')) continue;
    const eq = trimmed.indexOf('=');
    if (eq === -1) continue;
    const key = trimmed.slice(0, eq).trim();
    const value = trimmed.slice(eq + 1).trim();
    if (key && process.env[key] === undefined) process.env[key] = value;
  }
}

const databaseUrl = process.env.DATABASE_URL;
if (!databaseUrl) throw new Error('DATABASE_URL not set');

const recreate = process.argv.includes('--recreate');
const token = process.env.PERSISTENCE_CHECK_TOKEN ?? `persistence-${Date.now()}`;
const pgKey = 'infra.persistence_check';
const redisKey = 'infra:persistence_check';

function run(command, args, options = {}) {
  return execFileSync(command, args, {
    cwd: projectDir,
    stdio: options.capture ? ['ignore', 'pipe', 'pipe'] : 'inherit',
    encoding: 'utf8',
  });
}

function dockerCompose(args, options) {
  return run('docker', ['compose', ...args], options);
}

function dockerExec(container, args, options) {
  return run('docker', ['exec', container, ...args], options);
}

function waitForInfrastructure() {
  const deadline = Date.now() + 60_000;
  while (Date.now() < deadline) {
    try {
      dockerExec('mdv-dev-postgres', ['pg_isready', '-U', 'mdv', '-d', 'mercadodevida'], {
        capture: true,
      });
      dockerExec('mdv-dev-redis', ['redis-cli', 'ping'], { capture: true });
      return;
    } catch {
      Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 1000);
    }
  }
  throw new Error('PostgreSQL/Redis did not become ready in 60s');
}

async function writePostgresMarker() {
  const pool = new pg.Pool({ connectionString: databaseUrl });
  try {
    await pool.query(
      `INSERT INTO app_meta (key, value, updated_at)
       VALUES ($1, $2, now())
       ON CONFLICT (key) DO UPDATE SET value = EXCLUDED.value, updated_at = now()`,
      [pgKey, token],
    );
  } finally {
    await pool.end();
  }
}

async function readPostgresMarker() {
  const pool = new pg.Pool({ connectionString: databaseUrl });
  try {
    const result = await pool.query('SELECT value FROM app_meta WHERE key = $1', [pgKey]);
    return result.rows[0]?.value;
  } finally {
    await pool.end();
  }
}

function writeRedisMarker() {
  dockerExec('mdv-dev-redis', ['redis-cli', 'SET', redisKey, token]);
}

function readRedisMarker() {
  return dockerExec('mdv-dev-redis', ['redis-cli', 'GET', redisKey], { capture: true }).trim();
}

function printMounts() {
  const pgMount = run(
    'docker',
    [
      'inspect',
      'mdv-dev-postgres',
      '--format',
      '{{range .Mounts}}{{.Name}} -> {{.Destination}}{{println}}{{end}}',
    ],
    { capture: true },
  ).trim();
  const redisMount = run(
    'docker',
    [
      'inspect',
      'mdv-dev-redis',
      '--format',
      '{{range .Mounts}}{{.Name}} -> {{.Destination}}{{println}}{{end}}',
    ],
    { capture: true },
  ).trim();
  const redisAppendOnly = dockerExec(
    'mdv-dev-redis',
    ['redis-cli', 'CONFIG', 'GET', 'appendonly'],
    {
      capture: true,
    },
  ).trim();
  console.log(`PostgreSQL mount: ${pgMount}`);
  console.log(`Redis mount: ${redisMount}`);
  console.log(`Redis appendonly config:\n${redisAppendOnly}`);
}

console.log('[INFO] Starting infrastructure through docker compose...');
dockerCompose(['up', '-d', 'postgres', 'redis']);
waitForInfrastructure();
printMounts();

console.log(`[INFO] Writing persistence marker: ${token}`);
await writePostgresMarker();
writeRedisMarker();

if (recreate) {
  console.log('[INFO] Recreating PostgreSQL and Redis containers while keeping named volumes...');
  dockerCompose(['stop', 'postgres', 'redis']);
  dockerCompose(['rm', '-f', 'postgres', 'redis']);
  dockerCompose(['up', '-d', 'postgres', 'redis']);
} else {
  console.log('[INFO] Restarting PostgreSQL and Redis containers...');
  dockerCompose(['restart', 'postgres', 'redis']);
}
waitForInfrastructure();
printMounts();

const pgValue = await readPostgresMarker();
const redisValue = readRedisMarker();
if (pgValue !== token) {
  throw new Error(`PostgreSQL marker mismatch: expected ${token}, got ${pgValue ?? '<missing>'}`);
}
if (redisValue !== token) {
  throw new Error(`Redis marker mismatch: expected ${token}, got ${redisValue || '<missing>'}`);
}

console.log('[OK] PostgreSQL and Redis persistence verified');
