import { readJson, writeJson } from './storage';
import { randomBytes, scryptSync, timingSafeEqual } from 'node:crypto';
import type { Cookies } from '@sveltejs/kit';

const ADMIN_FILE = 'admin.json';
const SESSION_FILE = 'sessions.json';
const SESSION_COOKIE = 'gds_admin';
const SESSION_TTL_MS = 1000 * 60 * 60 * 24 * 7; // 7 days

type AdminRecord = {
  username: string;
  salt: string;
  hash: string;
  createdAt?: number;
};

type SessionRecord = {
  token: string;
  username: string;
  expiresAt: number;
};

function hashPassword(password: string, salt: string): string {
  return scryptSync(password, salt, 64).toString('hex');
}

function loadAdmins(): AdminRecord[] {
  const raw = readJson<AdminRecord | AdminRecord[] | null>(ADMIN_FILE, null);
  if (!raw) return [];
  if (Array.isArray(raw)) return raw;
  // Legacy single-record format — migrate in-memory (persisted on next write).
  return [raw];
}

function saveAdmins(admins: AdminRecord[]): void {
  writeJson(ADMIN_FILE, admins);
}

export function seedDefaultAdminIfMissing(): { username: string; tempPassword?: string } {
  const admins = loadAdmins();
  if (admins.length > 0) {
    // Ensure migration is persisted if legacy format was detected.
    const raw = readJson<AdminRecord | AdminRecord[] | null>(ADMIN_FILE, null);
    if (raw && !Array.isArray(raw)) saveAdmins(admins);
    return { username: admins[0].username };
  }
  const username = process.env.ADMIN_USERNAME || 'admin';
  const password = process.env.ADMIN_PASSWORD || 'changeme';
  const salt = randomBytes(16).toString('hex');
  const record: AdminRecord = {
    username,
    salt,
    hash: hashPassword(password, salt),
    createdAt: Date.now()
  };
  saveAdmins([record]);
  return { username, tempPassword: password };
}

export function verifyCredentials(username: string, password: string): boolean {
  const record = loadAdmins().find((a) => a.username === username);
  if (!record) return false;
  const candidate = Buffer.from(hashPassword(password, record.salt), 'hex');
  const stored = Buffer.from(record.hash, 'hex');
  if (candidate.length !== stored.length) return false;
  return timingSafeEqual(candidate, stored);
}

export function changePassword(
  username: string,
  currentPassword: string,
  newPassword: string
): boolean {
  if (!verifyCredentials(username, currentPassword)) return false;
  const admins = loadAdmins();
  const idx = admins.findIndex((a) => a.username === username);
  if (idx === -1) return false;
  const salt = randomBytes(16).toString('hex');
  admins[idx] = {
    ...admins[idx],
    salt,
    hash: hashPassword(newPassword, salt)
  };
  saveAdmins(admins);
  return true;
}

export type AdminSummary = { username: string; createdAt?: number };

export function listAdmins(): AdminSummary[] {
  return loadAdmins().map(({ username, createdAt }) => ({ username, createdAt }));
}

export function createAdmin(username: string, password: string): { ok: true } | { ok: false; error: string } {
  const clean = username.trim();
  if (!clean) return { ok: false, error: 'Username obbligatorio.' };
  if (clean.length < 3) return { ok: false, error: 'Username troppo corto (min 3 caratteri).' };
  if (!/^[a-zA-Z0-9_.-]+$/.test(clean)) {
    return { ok: false, error: 'Username: usa solo lettere, numeri, . _ -' };
  }
  if (password.length < 8) return { ok: false, error: 'Password troppo corta (min 8 caratteri).' };
  const admins = loadAdmins();
  if (admins.some((a) => a.username === clean)) {
    return { ok: false, error: 'Username già in uso.' };
  }
  const salt = randomBytes(16).toString('hex');
  admins.push({
    username: clean,
    salt,
    hash: hashPassword(password, salt),
    createdAt: Date.now()
  });
  saveAdmins(admins);
  return { ok: true };
}

export function deleteAdmin(username: string): { ok: true } | { ok: false; error: string } {
  const admins = loadAdmins();
  if (admins.length <= 1) {
    return { ok: false, error: 'Impossibile eliminare l\'ultimo amministratore.' };
  }
  const next = admins.filter((a) => a.username !== username);
  if (next.length === admins.length) return { ok: false, error: 'Amministratore non trovato.' };
  saveAdmins(next);
  // Revoke any active sessions for the removed user.
  const sessions = readJson<SessionRecord[]>(SESSION_FILE, []).filter((s) => s.username !== username);
  writeJson(SESSION_FILE, sessions);
  return { ok: true };
}

function loadSessions(): SessionRecord[] {
  const now = Date.now();
  const all = readJson<SessionRecord[]>(SESSION_FILE, []);
  const live = all.filter((s) => s.expiresAt > now);
  if (live.length !== all.length) writeJson(SESSION_FILE, live);
  return live;
}

export function createSession(username: string, cookies: Cookies): string {
  const sessions = loadSessions();
  const token = randomBytes(32).toString('hex');
  const record: SessionRecord = { token, username, expiresAt: Date.now() + SESSION_TTL_MS };
  sessions.push(record);
  writeJson(SESSION_FILE, sessions);
  cookies.set(SESSION_COOKIE, token, {
    path: '/',
    httpOnly: true,
    sameSite: 'lax',
    secure: process.env.NODE_ENV === 'production',
    maxAge: SESSION_TTL_MS / 1000
  });
  return token;
}

export function destroySession(cookies: Cookies): void {
  const token = cookies.get(SESSION_COOKIE);
  if (token) {
    const sessions = loadSessions().filter((s) => s.token !== token);
    writeJson(SESSION_FILE, sessions);
  }
  cookies.delete(SESSION_COOKIE, { path: '/' });
}

export function getSessionUser(cookies: Cookies): { username: string } | null {
  const token = cookies.get(SESSION_COOKIE);
  if (!token) return null;
  const session = loadSessions().find((s) => s.token === token);
  if (!session) return null;
  // If the user has been removed since, invalidate.
  const exists = loadAdmins().some((a) => a.username === session.username);
  if (!exists) return null;
  return { username: session.username };
}
