import type { Einstellungen, EinstellungenAnsicht, GeheimnisUebersicht, Software, SoftwareEingabe } from 'bibliothek-types';

/** Wertet eine Antwort aus, wirft bei Fehler mit der Server-Meldung. */
async function jsonOderFehler<T>(antwort: Response): Promise<T> {
  if (!antwort.ok) {
    const daten = (await antwort.json().catch(() => ({}))) as { fehler?: string };
    throw new Error(daten.fehler ?? `Fehler ${antwort.status}`);
  }
  return antwort.json() as Promise<T>;
}

/** Lädt den kompletten Software-Katalog vom Server. */
export async function ladeKatalog(): Promise<Software[]> {
  return jsonOderFehler(await fetch('/api/software'));
}

/** Fragt, ob der Zugriff direkt am Server (lokal) erfolgt — steuert die Sichtbarkeit der Verwaltung. */
export async function ladeUmgebung(): Promise<{ lokal: boolean }> {
  return jsonOderFehler(await fetch('/api/umgebung'));
}

export async function softwareAnlegen(eingabe: SoftwareEingabe): Promise<Software> {
  return jsonOderFehler(
    await fetch('/api/software', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(eingabe),
    })
  );
}

export async function softwareAktualisieren(id: number, eingabe: SoftwareEingabe): Promise<Software> {
  return jsonOderFehler(
    await fetch(`/api/software/${id}`, {
      method: 'PUT',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(eingabe),
    })
  );
}

export async function softwareLoeschen(id: number): Promise<void> {
  const antwort = await fetch(`/api/software/${id}`, { method: 'DELETE' });
  if (!antwort.ok) {
    throw new Error(`Löschen fehlgeschlagen (Status ${antwort.status})`);
  }
}

/** Hinterlegt eine Datei von Hand (Quellentyp „manuell"). */
export async function dateiHochladen(id: number, datei: File): Promise<Software> {
  return jsonOderFehler(
    await fetch(`/api/software/${id}/datei?dateiname=${encodeURIComponent(datei.name)}`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/octet-stream' },
      body: datei,
    })
  );
}

/** Löst einen sofortigen Abgleich der Bezugsquelle einer Software aus. */
export async function abgleichen(id: number): Promise<Software> {
  return jsonOderFehler(await fetch(`/api/software/${id}/abgleichen`, { method: 'POST' }));
}

/** Gleicht alle Einträge mit gesetzter Quelle ab. */
export async function alleAbgleichen(): Promise<Software[]> {
  return jsonOderFehler(await fetch('/api/abgleich/alle', { method: 'POST' }));
}

/** Stand der Bau-Geheimnisse einer Software (nur Namen, nie die Werte). */
export async function ladeGeheimnisse(id: number): Promise<GeheimnisUebersicht[]> {
  return jsonOderFehler(await fetch(`/api/software/${id}/geheimnisse`));
}

/** Speichert Bau-Geheimnisse. Ein leerer Wert lässt den bisherigen unverändert. */
export async function speichereGeheimnisse(id: number, werte: Array<{ name: string; wert: string }>): Promise<GeheimnisUebersicht[]> {
  return jsonOderFehler(
    await fetch(`/api/software/${id}/geheimnisse`, {
      method: 'PUT',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(werte),
    })
  );
}

/** URL für den Umzugs-Export (Katalog + Einstellungen, optional mit Geheimnissen). */
export function exportUrl(mitGeheimnissen: boolean): string {
  return `/api/export${mitGeheimnissen ? '?geheimnisse=ja' : ''}`;
}

/** Liest ein Umzugs-Paket ein und ersetzt damit den bisherigen Katalog. */
export async function importiereUmzugsPaket(paket: unknown): Promise<{ uebernommen: number; mitGeheimnissen: number; hinweis: string }> {
  return jsonOderFehler(
    await fetch('/api/import', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(paket),
    })
  );
}

/** Lädt die Einstellungen samt der daraus abgeleiteten Pfade (nur lokal erlaubt). */
export async function ladeEinstellungen(): Promise<EinstellungenAnsicht> {
  return jsonOderFehler(await fetch('/api/einstellungen'));
}

export async function speichereEinstellungen(einstellungen: Einstellungen): Promise<EinstellungenAnsicht> {
  return jsonOderFehler(
    await fetch('/api/einstellungen', {
      method: 'PUT',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(einstellungen),
    })
  );
}

/** URL zum Herunterladen mehrerer Programme als ZIP. */
export function downloadMehrereUrl(ids: number[], angegebenerName?: string): string {
  const parameter = new URLSearchParams({ ids: ids.join(',') });
  if (angegebenerName) {
    parameter.set('name', angegebenerName);
  }
  return `/api/download-mehrere?${parameter.toString()}`;
}

/** URL zum Herunterladen der Datei einer Software (optional mit angegebenem Namen fürs Protokoll). */
export function downloadUrl(id: number, angegebenerName?: string): string {
  const basis = `/api/software/${id}/download`;
  return angegebenerName ? `${basis}?name=${encodeURIComponent(angegebenerName)}` : basis;
}
