import { access, readdir } from "node:fs/promises";
import { join, resolve } from "node:path";

function executableName(tool: string): string {
  return process.platform === "win32" ? `${tool}.exe` : tool;
}

async function exists(path: string): Promise<boolean> {
  try {
    await access(path);
    return true;
  } catch {
    return false;
  }
}

export async function findPostgresTool(tool: "pg_dump" | "pg_restore" | "psql"): Promise<string> {
  const configured = process.env.POSTGRES_BIN?.trim();
  if (configured) {
    const candidate = resolve(configured, executableName(tool));
    if (!(await exists(candidate))) throw new Error("POSTGRES_TOOL_NOT_FOUND");
    return candidate;
  }

  if (process.platform === "win32") {
    const programFiles = process.env.ProgramFiles ?? "C:\\Program Files";
    const root = join(programFiles, "PostgreSQL");
    try {
      const versions = (await readdir(root, { withFileTypes: true }))
        .filter((entry) => entry.isDirectory())
        .map((entry) => entry.name)
        .sort((left, right) => right.localeCompare(left, undefined, { numeric: true }));
      for (const version of versions) {
        const candidate = join(root, version, "bin", executableName(tool));
        if (await exists(candidate)) return candidate;
      }
    } catch {
      // Fall through to PATH lookup.
    }
  }

  return executableName(tool);
}

export function postgresProcessEnvironment(connectionString: string): {
  readonly database: string;
  readonly environment: NodeJS.ProcessEnv;
} {
  const url = new URL(connectionString);
  if (url.protocol !== "postgresql:" && url.protocol !== "postgres:") {
    throw new Error("DATABASE_URL_INVALID");
  }
  const database = decodeURIComponent(url.pathname.replace(/^\//, ""));
  if (!database) throw new Error("DATABASE_URL_INVALID");
  const environment: NodeJS.ProcessEnv = {
    ...process.env,
    PGHOST: url.hostname,
    PGPORT: url.port || "5432",
    PGUSER: decodeURIComponent(url.username),
    PGPASSWORD: decodeURIComponent(url.password),
    PGDATABASE: database,
  };
  const sslMode = url.searchParams.get("sslmode");
  if (sslMode) environment.PGSSLMODE = sslMode;
  return { database, environment };
}
