import { spawnSync } from 'node:child_process';
import { createHash } from 'node:crypto';
import fs from 'node:fs';
import path from 'node:path';
import postgres from 'postgres';

export type SqlClient = ReturnType<typeof postgres>;

function loadEnvFile(filePath: string) {
  if (!fs.existsSync(filePath)) {
    return;
  }

  const content = fs.readFileSync(filePath, 'utf8');

  for (const rawLine of content.split(/\r?\n/)) {
    const line = rawLine.trim();

    if (!line || line.startsWith('#')) {
      continue;
    }

    const separatorIndex = line.indexOf('=');

    if (separatorIndex === -1) {
      continue;
    }

    const key = line.slice(0, separatorIndex).trim();
    let value = line.slice(separatorIndex + 1).trim();

    if (
      (value.startsWith('"') && value.endsWith('"')) ||
      (value.startsWith("'") && value.endsWith("'"))
    ) {
      value = value.slice(1, -1);
    }

    if (!(key in process.env)) {
      process.env[key] = value;
    }
  }
}

export function loadLocalEnv() {
  loadEnvFile(path.resolve(process.cwd(), '.env.local'));
  loadEnvFile(path.resolve(process.cwd(), '.env'));
}

export function requireEnv(name: string): string {
  const value = process.env[name]?.trim();

  if (!value) {
    throw new Error(`Missing required environment variable: ${name}`);
  }

  return value;
}

export function createSqlClient(): SqlClient {
  loadLocalEnv();
  return postgres(requireEnv('DATABASE_URL'), { prepare: false });
}

export function deterministicId(input: string): string {
  const digest = createHash('sha256').update(input).digest('hex');
  const part3 = `5${digest.slice(13, 16)}`;
  const part4 = `a${digest.slice(17, 20)}`;

  return [
    digest.slice(0, 8),
    digest.slice(8, 12),
    part3,
    part4,
    digest.slice(20, 32)
  ].join('-');
}

export const NODE_TS_RUNTIME_ARGS = [
  '--disable-warning=ExperimentalWarning',
  '--disable-warning=MODULE_TYPELESS_PACKAGE_JSON',
  '--experimental-strip-types'
];

export function runNodeScript(label: string, scriptPath: string, args: string[] = []) {
  const result = spawnSync(
    process.execPath,
    [...NODE_TS_RUNTIME_ARGS, scriptPath, ...args],
    {
      stdio: 'inherit',
      env: process.env
    }
  );

  if (result.status !== 0) {
    throw new Error(`[${label}] failed with exit code ${result.status ?? 1}`);
  }
}

export function runCommand(label: string, command: string, args: string[] = []) {
  const result = spawnSync(command, args, {
    stdio: 'inherit',
    env: process.env,
    shell: process.platform === 'win32'
  });

  if (result.status !== 0) {
    throw new Error(`[${label}] failed with exit code ${result.status ?? 1}`);
  }
}
