import * as fs from 'fs';
import * as path from 'path';
import type { Einstellungen } from 'bibliothek-types';
import { anwendungsDatenOrdner } from './pfade';

/**
 * Einstellungen liegen in `konfiguration.json` neben der Anwendung. Die Datei wird
 * beim ersten Start mit Standardwerten angelegt und kann über die Oberfläche
 * (nur lokal am Server) oder von Hand gepflegt werden.
 *
 * Umgebungsvariablen haben Vorrang — praktisch für abweichende Testläufe.
 */

const STANDARD_EINSTELLUNGEN: Einstellungen = {
  datenOrdner: '', // leer = Unterordner „data" im Anwendungsdaten-Ordner
  port: 3000,
  gitBenutzer: '', // leer = SSH-Konfiguration des Dienstbenutzers entscheidet
  gitSchluessel: '',
};

const konfigurationsPfad = path.join(anwendungsDatenOrdner(), 'konfiguration.json');

/** Liest die Konfigurationsdatei (und legt sie beim ersten Start an). */
function leseOderErzeuge(): Einstellungen {
  try {
    if (fs.existsSync(konfigurationsPfad)) {
      return normalisiere(JSON.parse(fs.readFileSync(konfigurationsPfad, 'utf8')) as Partial<Einstellungen>);
    }
    const standard = { ...STANDARD_EINSTELLUNGEN };
    schreibeDatei(standard);
    return standard;
  } catch (fehler) {
    console.warn(`konfiguration.json konnte nicht gelesen werden, Standardwerte greifen: ${String(fehler)}`);
    return { ...STANDARD_EINSTELLUNGEN };
  }
}

// Beim Laden des Moduls einlesen, damit auch die Datenbank-Schicht schon den
// konfigurierten Ordner sieht (sie wird beim Start direkt initialisiert).
let gelesene: Einstellungen = leseOderErzeuge();

/** Speichert geänderte Einstellungen. Der Datenordner wirkt erst nach einem Neustart. */
export function speichereEinstellungen(neue: Partial<Einstellungen>): Einstellungen {
  gelesene = normalisiere({ ...gelesene, ...neue });
  schreibeDatei(gelesene);
  return gelesene;
}

export function aktuelleEinstellungen(): Einstellungen {
  return gelesene;
}

export function konfigurationsDatei(): string {
  return konfigurationsPfad;
}

/** Tatsächlich genutzter Datenordner — Umgebungsvariable vor Einstellung vor Standard. */
export function effektiverDatenOrdner(): string {
  const ausUmgebung = process.env.DATEN_ORDNER?.trim();
  if (ausUmgebung) {
    return path.resolve(ausUmgebung);
  }
  if (gelesene.datenOrdner.trim()) {
    return path.resolve(gelesene.datenOrdner.trim());
  }
  return path.join(anwendungsDatenOrdner(), 'data');
}

/** Tatsächlich genutzter Port — Umgebungsvariable vor Einstellung vor Standard. */
export function effektiverPort(): number {
  const ausUmgebung = Number(process.env.PORT);
  if (Number.isInteger(ausUmgebung) && ausUmgebung > 0) {
    return ausUmgebung;
  }
  return gelesene.port;
}

function normalisiere(eingabe: Partial<Einstellungen>): Einstellungen {
  const port = Number(eingabe.port);
  return {
    datenOrdner: typeof eingabe.datenOrdner === 'string' ? eingabe.datenOrdner.trim() : '',
    port: Number.isInteger(port) && port > 0 && port < 65536 ? port : STANDARD_EINSTELLUNGEN.port,
    // Nur was als SSH-Benutzername taugt — schützt zugleich vor Einschleusen in die Befehlszeile.
    gitBenutzer: /^[A-Za-z0-9._-]*$/.test(String(eingabe.gitBenutzer ?? '').trim()) ? String(eingabe.gitBenutzer ?? '').trim() : '',
    gitSchluessel: String(eingabe.gitSchluessel ?? '').trim(),
  };
}

/**
 * Baut den SSH-Aufruf für Git aus den Einstellungen. Leer, wenn nichts gepflegt ist —
 * dann greift die SSH-Konfiguration des Dienstbenutzers wie bisher.
 */
export function gitSshBefehl(): string {
  const teile = ['ssh'];
  if (gelesene.gitBenutzer) {
    teile.push('-o', `User=${gelesene.gitBenutzer}`);
  }
  if (gelesene.gitSchluessel) {
    teile.push('-i', `"${gelesene.gitSchluessel.replace(/\\/g, '/')}"`);
  }
  return teile.length > 1 ? teile.join(' ') : '';
}

function schreibeDatei(einstellungen: Einstellungen): void {
  fs.mkdirSync(path.dirname(konfigurationsPfad), { recursive: true });
  fs.writeFileSync(konfigurationsPfad, `${JSON.stringify(einstellungen, null, 2)}\n`);
}
