import crypto from "node:crypto";

import db from "./db.js";

const getStmt = db.prepare("SELECT value FROM settings WHERE key = ?");
const upsertStmt = db.prepare("INSERT INTO settings (key, value, updated_at) VALUES (?, ?, ?) ON CONFLICT(key) DO UPDATE SET value=excluded.value, updated_at=excluded.updated_at");
const deleteStmt = db.prepare("DELETE FROM settings WHERE key = ?");
const listStmt = db.prepare("SELECT key, value FROM settings");

export type SettingKey =
  | "paperlessBaseUrl"
  | "paperlessExternalUrl"
  | "paperlessToken"
  | "schedulerIntervalMinutes"
  | "alertDaysBefore"
  | "mailServer"
  | "mailPort"
  | "mailUsername"
  | "mailPassword"
  | "mailUseTls"
  | "mailFrom"
  | "mailTo"
  | "ntfyServerUrl"
  | "ntfyTopic"
  | "ntfyToken"
  | "ntfyPriority"
  | "authUsername"
  | "authPassword"
  | "icalSecret";

export type StoredSettings = Partial<Record<SettingKey, unknown>>;

export function getSetting<T = unknown>(key: SettingKey): T | undefined {
  const row = getStmt.get(key) as { value: string } | undefined;
  if (!row || typeof row.value !== "string") {
    return undefined;
  }
  try {
    return JSON.parse(row.value) as T;
  } catch (_error) {
    return undefined;
  }
}

export function setSetting(key: SettingKey, value: unknown): void {
  if (value === undefined || value === null || value === "") {
    deleteStmt.run(key);
    return;
  }
  const now = new Date().toISOString();
  upsertStmt.run(key, JSON.stringify(value), now);
}

export function removeSetting(key: SettingKey): void {
  deleteStmt.run(key);
}

export function listSettings(): StoredSettings {
  const rows = listStmt.all() as Array<{ key: string; value: string }>;
  const result: StoredSettings = {};
  for (const row of rows) {
    try {
      result[row.key as SettingKey] = JSON.parse(row.value);
    } catch (_error) {
      // ignore bad data
    }
  }
  return result;
}

export function ensureSetting(key: SettingKey, generator: () => unknown): unknown {
  const existing = getSetting(key);
  if (existing !== undefined) {
    return existing;
  }
  const value = generator();
  setSetting(key, value);
  return value;
}

export function generateSecret(length = 32): string {
  return crypto.randomBytes(length).toString("hex");
}
