import fs from "node:fs";
import path from "node:path";
import { randomBytes } from "node:crypto";
import { config as loadDotenv, parse as parseEnvFileContents } from "dotenv";
import { resolveConfigPath } from "./store.js";

const JWT_SECRET_ENV_KEY = "PAPERCLIP_AGENT_JWT_SECRET";
function resolveEnvFilePath(configPath?: string) {
  return path.resolve(path.dirname(resolveConfigPath(configPath)), ".env");
}
const loadedEnvFiles = new Set<string>();

function isNonEmpty(value: unknown): value is string {
  return typeof value === "string" && value.trim().length > 0;
}

function parseEnvFile(contents: string) {
  try {
    return parseEnvFileContents(contents);
  } catch {
    return {};
  }
}

function formatEnvValue(value: string): string {
  if (/^[A-Za-z0-9_./:@-]+$/.test(value)) {
    return value;
  }
  return JSON.stringify(value);
}

function renderEnvFile(entries: Record<string, string>) {
  const lines = [
    "# Paperclip environment variables",
    "# Generated by Paperclip CLI commands",
    ...Object.entries(entries).map(([key, value]) => `${key}=${formatEnvValue(value)}`),
    "",
  ];
  return lines.join("\n");
}

export function resolvePaperclipEnvFile(configPath?: string): string {
  return resolveEnvFilePath(configPath);
}

export function resolveAgentJwtEnvFile(configPath?: string): string {
  return resolveEnvFilePath(configPath);
}

export function loadPaperclipEnvFile(configPath?: string): void {
  loadAgentJwtEnvFile(resolveEnvFilePath(configPath));
}

export function loadAgentJwtEnvFile(filePath = resolveEnvFilePath()): void {
  if (loadedEnvFiles.has(filePath)) return;

  if (!fs.existsSync(filePath)) return;
  loadedEnvFiles.add(filePath);
  loadDotenv({ path: filePath, override: false, quiet: true });
}

export function readAgentJwtSecretFromEnv(configPath?: string): string | null {
  loadAgentJwtEnvFile(resolveEnvFilePath(configPath));
  const raw = process.env[JWT_SECRET_ENV_KEY];
  return isNonEmpty(raw) ? raw!.trim() : null;
}

export function readAgentJwtSecretFromEnvFile(filePath = resolveEnvFilePath()): string | null {
  if (!fs.existsSync(filePath)) return null;

  const raw = fs.readFileSync(filePath, "utf-8");
  const values = parseEnvFile(raw);
  const value = values[JWT_SECRET_ENV_KEY];
  return isNonEmpty(value) ? value!.trim() : null;
}

export function ensureAgentJwtSecret(configPath?: string): { secret: string; created: boolean } {
  const existingEnv = readAgentJwtSecretFromEnv(configPath);
  if (existingEnv) {
    return { secret: existingEnv, created: false };
  }

  const envFilePath = resolveEnvFilePath(configPath);
  const existingFile = readAgentJwtSecretFromEnvFile(envFilePath);
  const secret = existingFile ?? randomBytes(32).toString("hex");
  const created = !existingFile;

  if (!existingFile) {
    writeAgentJwtEnv(secret, envFilePath);
  }

  return { secret, created };
}

export function writeAgentJwtEnv(secret: string, filePath = resolveEnvFilePath()): void {
  mergePaperclipEnvEntries({ [JWT_SECRET_ENV_KEY]: secret }, filePath);
}

export function readPaperclipEnvEntries(filePath = resolveEnvFilePath()): Record<string, string> {
  if (!fs.existsSync(filePath)) return {};
  return parseEnvFile(fs.readFileSync(filePath, "utf-8"));
}

export function writePaperclipEnvEntries(entries: Record<string, string>, filePath = resolveEnvFilePath()): void {
  const dir = path.dirname(filePath);
  fs.mkdirSync(dir, { recursive: true });
  fs.writeFileSync(filePath, renderEnvFile(entries), {
    mode: 0o600,
  });
}

export function mergePaperclipEnvEntries(
  entries: Record<string, string>,
  filePath = resolveEnvFilePath(),
): Record<string, string> {
  const current = readPaperclipEnvEntries(filePath);
  const next = {
    ...current,
    ...Object.fromEntries(
      Object.entries(entries).filter(([, value]) => typeof value === "string" && value.trim().length > 0),
    ),
  };
  writePaperclipEnvEntries(next, filePath);
  return next;
}
