import { LitElement, html, nothing } from 'lit';
import { customElement, state } from 'lit/decorators.js';
import { event, type EventRef } from '@dh-software/lit-extensions';
import type { DhInput } from '@dh-software/dh-components';
import type { EinstellungenAnsicht } from 'bibliothek-types';
import { ladeEinstellungen, speichereEinstellungen, exportUrl, importiereUmzugsPaket } from '../api-client';

/** Einstellungen der Anwendung — nur direkt am Server erreichbar. */
@customElement('bibliothek-einstellungen')
export class BibliothekEinstellungen extends LitElement {
  @state() private ansicht?: EinstellungenAnsicht;
  @state() private datenOrdner = '';
  @state() private port = 3000;
  @state() private gitBenutzer = '';
  @state() private gitSchluessel = '';
  @state() private meldung = '';
  @state() private fehler = '';
  @state() private speichert = false;

  @event({ bubbles: true, composed: true }, 'geschlossen')
  private geschlossen!: EventRef<void>;

  @event({ bubbles: true, composed: true }, 'umzugAbgeschlossen')
  private umzugAbgeschlossen!: EventRef<void>;

  // Light DOM, damit das globale dh-components-Theme greift.
  createRenderRoot() {
    return this;
  }

  connectedCallback(): void {
    super.connectedCallback();
    this.einstellungenLaden();
  }

  render() {
    if (!this.ansicht) {
      return html`<dh-card variant="outlined"><span slot="content">Einstellungen werden geladen …</span></dh-card>`;
    }
    const neustartNoetig =
      this.datenOrdner.trim() !== this.ansicht.einstellungen.datenOrdner || this.port !== this.ansicht.laufenderPort;
    return html`
      <dh-card variant="outlined" no-hover-effect no-click-effect>
        <span slot="header">Einstellungen</span>
        <div slot="content">
          <dh-form-grid>
            <dh-form-field label="Datenordner" span="2">
              <dh-input
                type="text"
                placeholder=${'leer = Standardordner unter ProgramData'}
                .value=${this.datenOrdner}
                @input=${this.beiDatenOrdner}
              ></dh-input>
              <span class="feldhinweis">Hier liegen die Datenbank und alle bereitgestellten Programm-Dateien.</span>
            </dh-form-field>
            <dh-form-field label="Port">
              <dh-input type="number" min="1" max="65535" .value=${String(this.port)} @input=${this.beiPort}></dh-input>
            </dh-form-field>
            <dh-form-field label="Git-Benutzer (für interne Tools)">
              <dh-input
                type="text"
                placeholder="leer = SSH-Konfiguration des Dienstbenutzers"
                .value=${this.gitBenutzer}
                @input=${this.beiGitBenutzer}
              ></dh-input>
              <span class="feldhinweis">
                Gilt für alle Git-Quellen. Dadurch bleiben die Katalog-URLs frei von Konto-Angaben — ein
                Kontowechsel ist eine Änderung hier statt an jedem Eintrag.
              </span>
            </dh-form-field>
            <dh-form-field label="SSH-Schlüssel (optional)">
              <dh-input
                type="text"
                placeholder="C:\\ProgramData\\Software-Bibliothek\\id_bibliothek"
                .value=${this.gitSchluessel}
                @input=${this.beiGitSchluessel}
              ></dh-input>
              <span class="feldhinweis">
                Nur nötig, wenn das Konto, unter dem die Bibliothek läuft, keinen eigenen SSH-Schlüssel hat —
                sonst leer lassen. Wird relevant beim Betrieb als Dienst oder nach einem Serverumzug.
              </span>
            </dh-form-field>
          </dh-form-grid>

          <dl class="einstellungen-infos">
            <dt>Datenordner (aktuell genutzt)</dt>
            <dd>${this.ansicht.effektiverDatenOrdner}</dd>
            <dt>Konfigurationsdatei</dt>
            <dd>${this.ansicht.konfigurationsDatei}</dd>
            <dt>Laufender Port</dt>
            <dd>${this.ansicht.laufenderPort}</dd>
          </dl>

          <div class="umzug">
            <h3>Umzug auf einen anderen Rechner</h3>
            <p class="feldhinweis">
              Gesichert werden Katalog, Bezugsquellen und Einstellungen — wenige Kilobyte. Die geholten
              Programm-Dateien kommen nicht mit; die holt der Abgleich auf dem neuen Rechner selbst wieder.
            </p>
            <div class="umzug-aktionen">
              <dh-button buttonText="Exportieren" variant="standard" @click=${this.beiExport}></dh-button>
              <dh-button buttonText="Mit Schlüsseln exportieren" variant="standard" @click=${this.beiExportMitGeheimnissen}></dh-button>
              <dh-button buttonText="Paket einlesen" variant="standard" @click=${this.beiImportWaehlen}></dh-button>
              <input id="import-datei" type="file" accept="application/json,.json" hidden @change=${this.beiImportDatei} />
            </div>
            <p class="feldhinweis warnhinweis">
              „Mit Schlüsseln" schreibt die hinterlegten Werte im Klartext in die Datei — nur bewusst nutzen
              und die Datei danach sicher aufbewahren bzw. löschen.
            </p>
          </div>

          ${neustartNoetig ? html`<p class="hinweis">Änderungen an Datenordner oder Port wirken erst nach einem Neustart der Anwendung.</p>` : nothing}
          ${this.meldung ? html`<p class="hinweis">${this.meldung}</p>` : nothing}
        </div>
        <div slot="actions">
          ${this.fehler ? html`<span class="fehler">${this.fehler}</span>` : nothing}
          <dh-button buttonText="Schließen" variant="standard" @click=${this.beiSchliessen}></dh-button>
          <dh-button
            buttonText=${this.speichert ? 'Speichert…' : 'Speichern'}
            variant="filled"
            ?disabled=${this.speichert}
            @click=${this.beiSpeichern}
          ></dh-button>
        </div>
      </dh-card>
    `;
  }

  private async einstellungenLaden(): Promise<void> {
    try {
      this.ansicht = await ladeEinstellungen();
      this.datenOrdner = this.ansicht.einstellungen.datenOrdner;
      this.port = this.ansicht.einstellungen.port;
      this.gitBenutzer = this.ansicht.einstellungen.gitBenutzer;
      this.gitSchluessel = this.ansicht.einstellungen.gitSchluessel;
    } catch (fehler) {
      this.fehler = fehler instanceof Error ? fehler.message : 'Einstellungen konnten nicht geladen werden.';
    }
  }

  private beiDatenOrdner(ereignis: Event): void {
    this.datenOrdner = (ereignis.target as DhInput).value;
  }

  private beiPort(ereignis: Event): void {
    this.port = Number((ereignis.target as DhInput).value) || 0;
  }

  private beiGitBenutzer(ereignis: Event): void {
    this.gitBenutzer = (ereignis.target as DhInput).value;
  }

  private beiGitSchluessel(ereignis: Event): void {
    this.gitSchluessel = (ereignis.target as DhInput).value;
  }

  private beiSchliessen(): void {
    this.geschlossen.dispatch();
  }

  private beiExport(): void {
    window.location.href = exportUrl(false);
  }

  private beiExportMitGeheimnissen(): void {
    if (confirm('Die Datei enthält dann die hinterlegten Schlüssel im Klartext. Wirklich so exportieren?')) {
      window.location.href = exportUrl(true);
    }
  }

  private beiImportWaehlen(): void {
    this.querySelector<HTMLInputElement>('#import-datei')?.click();
  }

  private async beiImportDatei(ereignis: Event): Promise<void> {
    const feld = ereignis.target as HTMLInputElement;
    const datei = feld.files?.[0];
    feld.value = ''; // erlaubt, dieselbe Datei erneut zu wählen
    if (!datei) {
      return;
    }
    if (!confirm('Der bisherige Katalog wird dabei vollständig ersetzt. Fortfahren?')) {
      return;
    }
    this.fehler = '';
    this.meldung = '';
    try {
      const ergebnis = await importiereUmzugsPaket(JSON.parse(await datei.text()));
      this.meldung = `${ergebnis.uebernommen} Einträge übernommen${ergebnis.mitGeheimnissen > 0 ? `, davon ${ergebnis.mitGeheimnissen} mit Schlüsseln` : ''}. ${ergebnis.hinweis}`;
      this.umzugAbgeschlossen.dispatch();
    } catch (fehler) {
      this.fehler = fehler instanceof Error ? fehler.message : 'Paket konnte nicht eingelesen werden.';
    }
  }

  private async beiSpeichern(): Promise<void> {
    this.speichert = true;
    this.fehler = '';
    this.meldung = '';
    try {
      this.ansicht = await speichereEinstellungen({
        datenOrdner: this.datenOrdner.trim(),
        port: this.port,
        gitBenutzer: this.gitBenutzer.trim(),
        gitSchluessel: this.gitSchluessel.trim(),
      });
      this.datenOrdner = this.ansicht.einstellungen.datenOrdner;
      this.port = this.ansicht.einstellungen.port;
      this.gitBenutzer = this.ansicht.einstellungen.gitBenutzer;
      this.gitSchluessel = this.ansicht.einstellungen.gitSchluessel;
      this.meldung = 'Gespeichert. Datenordner und Port gelten ab dem nächsten Start.';
    } catch (fehler) {
      this.fehler = fehler instanceof Error ? fehler.message : 'Speichern fehlgeschlagen.';
    } finally {
      this.speichert = false;
    }
  }
}

declare global {
  interface HTMLElementTagNameMap {
    'bibliothek-einstellungen': BibliothekEinstellungen;
  }
}
