// Réglages de la découverte auto des repos, persistés dans la table `settings` (clé/valeur).
// Frontière de sécurité : ces clés sont NON sensibles et n'entrent dans l'allow-list du PATCH
// /api/v1/settings que via les validateurs ci-dessous. Aucun secret ne transite par ici.
import { getSetting } from '../db/index.js';
import type { Db } from '../db/index.js';
import { isSafeAbsolutePath } from './git.js';

export const SCAN_ROOTS_KEY = 'scan_roots';
export const SCAN_INTERVAL_KEY = 'scan_interval_min';

/** Intervalle par défaut du re-scan périodique (minutes). 0 = désactivé. */
export const DEFAULT_SCAN_INTERVAL_MIN = 5;
/** Borne haute de l'intervalle (24 h) et nombre maximal de racines. */
export const MAX_SCAN_INTERVAL_MIN = 1440;
export const MAX_SCAN_ROOTS = 16;

/**
 * Racines à scanner. Défaut : AUCUNE racine → aucun scan (clean install).
 * L'utilisateur ajoute ses racines via Réglages → Découverte. Lecture tolérante (JSON malformé → []).
 */
export function readScanRoots(db: Db): string[] {
  const raw = getSetting(db, SCAN_ROOTS_KEY);
  if (!raw) return [];
  return normalizeScanRoots(safeParse(raw)) ?? [];
}

/** Intervalle périodique en minutes (0 = désactivé). Défaut DEFAULT_SCAN_INTERVAL_MIN. */
export function readScanIntervalMin(db: Db): number {
  const raw = getSetting(db, SCAN_INTERVAL_KEY);
  if (raw === null) return DEFAULT_SCAN_INTERVAL_MIN;
  const n = Number(raw);
  return Number.isInteger(n) && n >= 0 && n <= MAX_SCAN_INTERVAL_MIN ? n : DEFAULT_SCAN_INTERVAL_MIN;
}

/**
 * Valide/normalise une liste de racines : tableau de chemins absolus normalisés (isSafeAbsolutePath),
 * jamais `/` (scan catastrophique), dédupliqués, ≤ MAX_SCAN_ROOTS. Retourne null si invalide (⇒ 400).
 * Une liste vide est valide (revient au défaut côté lecture).
 */
export function normalizeScanRoots(raw: unknown): string[] | null {
  if (!Array.isArray(raw)) return null;
  if (raw.length > MAX_SCAN_ROOTS) return null;
  const out: string[] = [];
  for (const item of raw) {
    if (typeof item !== 'string') return null;
    const p = item.trim();
    if (!isSafeAbsolutePath(p) || p === '/') return null;
    if (!out.includes(p)) out.push(p);
  }
  return out;
}

/** Valide un intervalle (entier 0–MAX_SCAN_INTERVAL_MIN). Retourne null si invalide. */
export function normalizeScanIntervalMin(raw: unknown): number | null {
  if (typeof raw !== 'number' || !Number.isInteger(raw)) return null;
  if (raw < 0 || raw > MAX_SCAN_INTERVAL_MIN) return null;
  return raw;
}

function safeParse(raw: string): unknown {
  try {
    return JSON.parse(raw);
  } catch {
    return null;
  }
}
