import { mkdirSync, writeFileSync, chmodSync, appendFileSync } from "node:fs";
import { appendFile, chmod, writeFile } from "node:fs/promises";
import { createLogger } from "./logger.js";

const log = createLogger("fs-permissions");

/**
 * Create a directory with restrictive permissions (0700 — owner-only).
 * On Windows, chmod may be a no-op; errors are caught and logged.
 */
export function ensureSecureDir(dirPath: string): void {
  mkdirSync(dirPath, { recursive: true, mode: 0o700 });
  try {
    chmodSync(dirPath, 0o700);
  } catch (err) {
    log.debug({ dirPath, err }, "chmod on directory not supported (expected on Windows)");
  }
}

/**
 * Write a file with restrictive permissions (0600 — owner read/write only).
 * Writes the file first, then applies chmod. On Windows, chmod may be a
 * no-op; errors are caught and logged.
 */
export function writeSecureFile(filePath: string, data: string, options?: { encoding?: BufferEncoding }): void {
  const encoding = options?.encoding ?? "utf-8";
  writeFileSync(filePath, data, { encoding, mode: 0o600 });
  try {
    chmodSync(filePath, 0o600);
  } catch (err) {
    log.debug({ filePath, err }, "chmod on file not supported (expected on Windows)");
  }
}

/**
 * Async variant of writeSecureFile for non-blocking I/O.
 * Uses Bun.write when available (production), falls back to node:fs/promises
 * writeFile in other environments (e.g. vitest workers).
 */
export async function writeSecureFileAsync(filePath: string, data: string): Promise<void> {
  if (typeof Bun !== "undefined" && Bun.write) {
    await Bun.write(filePath, data);
  } else {
    await writeFile(filePath, data, { encoding: "utf-8", mode: 0o600 });
  }
  try {
    await chmod(filePath, 0o600);
  } catch (err) {
    log.debug({ filePath, err }, "chmod on file not supported (expected on Windows)");
  }
}

/**
 * Append to a file with restrictive permissions (0600 — owner read/write only).
 * On first write the file is created with mode 0o600. Subsequent appends
 * re-apply chmod to ensure the permission stays correct even if the file
 * was recreated externally.
 */
export function appendSecureFile(filePath: string, data: string): void {
  appendFileSync(filePath, data, { mode: 0o600 });
  try {
    chmodSync(filePath, 0o600);
  } catch (err) {
    log.debug({ filePath, err }, "chmod on file not supported (expected on Windows)");
  }
}

/**
 * Async variant of appendSecureFile. Sets mode 0o600 on file creation;
 * skips redundant chmod on each append (permissions are locked at creation).
 * Suitable for high-throughput append-only files like recordings.
 */
export async function appendSecureFileAsync(filePath: string, data: string): Promise<void> {
  await appendFile(filePath, data, { mode: 0o600 });
}
