<script lang="ts">
  import {
    AlertTriangle,
    ArchiveRestore,
    Box,
    Check,
    CircleDashed,
    Download,
    HardDriveDownload,
    Link2,
    LoaderCircle,
    PackageCheck,
    Plus,
    RefreshCw,
    ShieldCheck,
    Trash2,
    X,
  } from "@lucide/svelte";
  import type { AppLanguage, GitLfsPattern, GitLfsStatus } from "../types";

  interface Props {
    status: GitLfsStatus | null;
    language: AppLanguage;
    isLoading: boolean;
    isBusy: boolean;
    error?: string;
    onRefresh: () => void | Promise<void>;
    onInstall: () => boolean | void | Promise<boolean | void>;
    onTrack: (pattern: string, lockable: boolean) => boolean | Promise<boolean>;
    onUntrack: (pattern: string) => void | Promise<void>;
    onPull: () => void | Promise<void>;
    onPrune: () => void | Promise<void>;
    onClose: () => void;
  }

  let {
    status = null,
    language = "en",
    isLoading = false,
    isBusy = false,
    error = "",
    onRefresh = () => {},
    onInstall = () => {},
    onTrack = () => false,
    onUntrack = () => {},
    onPull = () => {},
    onPrune = () => {},
    onClose = () => {},
  }: Props = $props();

  let pattern = $state("");
  let lockable = $state(false);
  let isGerman = $derived(language === "de");
  let setupReady = $derived(Boolean(status?.filters_configured && status?.hook_installed));
  let downloadedCount = $derived(status?.files.filter((file) => file.downloaded).length ?? 0);
  let totalSize = $derived(status?.files.reduce((sum, file) => sum + file.size, 0) ?? 0);

  function formatBytes(value: number): string {
    if (!value) return "—";
    const units = ["B", "KB", "MB", "GB", "TB"];
    const index = Math.min(Math.floor(Math.log(value) / Math.log(1024)), units.length - 1);
    const amount = value / 1024 ** index;
    return `${amount >= 10 || index === 0 ? amount.toFixed(0) : amount.toFixed(1)} ${units[index]}`;
  }

  function versionLabel(value: string | null | undefined): string {
    return value?.match(/git-lfs\/([^\s]+)/)?.[1] ?? value ?? "—";
  }

  function canRemove(item: GitLfsPattern): boolean {
    return item.source === ".gitattributes";
  }

  async function submitPattern(event: SubmitEvent) {
    event.preventDefault();
    const value = pattern.trim();
    if (!value || !setupReady) return;
    if (await onTrack(value, lockable)) {
      pattern = "";
      lockable = false;
    }
  }

  async function confirmPrune() {
    const confirmed = window.confirm(isGerman
      ? "Nicht mehr benötigte lokale LFS-Objekte sicher bereinigen? Nicht gepushte und aktuell verwendete Objekte bleiben erhalten."
      : "Safely prune unused local LFS objects? Unpushed and currently used objects are retained.");
    if (confirmed) await onPrune();
  }
</script>

<div class="dialog-backdrop" role="presentation">
  <div class="dialog lfs-dialog" role="dialog" aria-modal="true" aria-labelledby="lfs-dialog-title">
    <header class="dialog-header lfs-dialog-header">
      <div class="lfs-heading">
        <span class="lfs-mark" aria-hidden="true"><Box size={19} /></span>
        <div>
          <span class="eyebrow">Large file storage</span>
          <p class="dialog-title" id="lfs-dialog-title">Git LFS</p>
        </div>
      </div>
      <div class="dialog-header-actions">
        <button class="btn-sm" type="button" onclick={onRefresh} disabled={isBusy || isLoading}>
          <RefreshCw class={isLoading ? "spin" : undefined} size={15} aria-hidden="true" />
          {isGerman ? "Prüfen" : "Check"}
        </button>
        <button class="btn-sm dialog-close" type="button" onclick={onClose} disabled={isBusy} aria-label={isGerman ? "Schließen" : "Close"}>
          <X size={16} aria-hidden="true" />
        </button>
      </div>
    </header>

    <div class="lfs-main">
      {#if error}
        <div class="lfs-error" role="alert"><AlertTriangle size={15} aria-hidden="true" />{error}</div>
      {/if}

      {#if isLoading && !status}
        <div class="lfs-loading"><LoaderCircle class="spin" size={22} aria-hidden="true" /><span>{isGerman ? "Git LFS wird geprüft…" : "Inspecting Git LFS…"}</span></div>
      {:else if status}
        <div class="lfs-content">
        <section class="lfs-diagnostics" aria-label={isGerman ? "LFS-Diagnose" : "LFS diagnostics"}>
          <article class:ready={status.available} class:error={!status.available}>
            <span class="diagnostic-icon">{#if status.available}<PackageCheck size={18} />{:else}<AlertTriangle size={18} />{/if}</span>
            <div><small>01 · {isGerman ? "Erweiterung" : "Extension"}</small><strong>{status.available ? `Git LFS ${versionLabel(status.version)}` : (isGerman ? "Nicht gefunden" : "Not found")}</strong><span>{status.bundled ? (isGerman ? "Mit Gitty gebündelt" : "Bundled with Gitty") : (isGerman ? "Systeminstallation" : "System installation")}</span></div>
          </article>
          <span class:ready={status.available} class="diagnostic-link" aria-hidden="true"><Link2 size={14} /></span>
          <article class:ready={setupReady} class:warning={status.available && !setupReady}>
            <span class="diagnostic-icon">{#if setupReady}<ShieldCheck size={18} />{:else}<CircleDashed size={18} />{/if}</span>
            <div><small>02 · Repository</small><strong>{setupReady ? (isGerman ? "Aktiv" : "Active") : (isGerman ? "Einrichtung nötig" : "Setup required")}</strong><span>{status.filters_configured ? "Filter ✓" : "Filter —"} · {status.hook_installed ? "Pre-push ✓" : "Pre-push —"}</span></div>
          </article>
          <span class:ready={setupReady} class="diagnostic-link" aria-hidden="true"><Link2 size={14} /></span>
          <article class:ready={status.files.length > 0}>
            <span class="diagnostic-icon"><ArchiveRestore size={18} /></span>
            <div><small>03 · {isGerman ? "Objekte" : "Objects"}</small><strong>{status.files.length} {isGerman ? "Dateien" : "files"}</strong><span>{downloadedCount} {isGerman ? "lokal" : "local"} · {formatBytes(totalSize)}</span></div>
          </article>
        </section>

        {#if !status.available}
          <section class="lfs-missing">
            <span class="lfs-missing-icon"><AlertTriangle size={22} aria-hidden="true" /></span>
            <div>
              <strong>{isGerman ? "Git LFS ist nicht ausführbar" : "Git LFS cannot be started"}</strong>
              <p>{isGerman ? "Gitty liefert Git LFS normalerweise mit. Installiere Gitty erneut oder installiere git-lfs systemweit und starte die App neu." : "Gitty normally includes Git LFS. Reinstall Gitty or install git-lfs system-wide, then restart the app."}</p>
            </div>
          </section>
        {:else}
          {#if !setupReady}
            <section class="lfs-setup-card">
              <div><strong>{isGerman ? "Für dieses Repository aktivieren" : "Activate for this repository"}</strong><p>{isGerman ? "Richtet Clean-/Smudge-Filter lokal ein und installiert den Pre-push-Hook. Globale Git-Einstellungen bleiben unverändert." : "Configures local clean/smudge filters and installs the pre-push hook. Global Git settings remain unchanged."}</p></div>
              <button class="btn-primary" type="button" onclick={onInstall} disabled={isBusy}><ShieldCheck size={15} aria-hidden="true" />{isGerman ? "LFS aktivieren" : "Activate LFS"}</button>
            </section>
          {/if}

          <div class="lfs-grid">
            <section class="lfs-panel patterns-panel">
              <header><div><span class="eyebrow">Tracking rules</span><h3>{isGerman ? "Muster" : "Patterns"}</h3></div><span>{status.patterns.length}</span></header>
              <form class="lfs-track-form" onsubmit={submitPattern}>
                <label><span>{isGerman ? "Neues Muster" : "New pattern"}</span><input type="text" bind:value={pattern} disabled={isBusy || !setupReady} autocomplete="off" spellcheck="false" placeholder="*.psd, Assets/**, video.mp4" /></label>
                <label class="lfs-lockable"><input type="checkbox" bind:checked={lockable} disabled={isBusy || !setupReady} /><span><strong>Lockable</strong><small>{isGerman ? "Schreibgeschützt, solange nicht gesperrt" : "Read-only until locked"}</small></span></label>
                <button class="btn-primary" type="submit" disabled={isBusy || !setupReady || !pattern.trim()}><Plus size={15} aria-hidden="true" />{isGerman ? "Hinzufügen" : "Add"}</button>
              </form>

              <div class="lfs-pattern-list">
                {#if status.patterns.length === 0}
                  <div class="lfs-empty"><Box size={20} aria-hidden="true" /><span>{isGerman ? "Noch keine Dateien werden über LFS verwaltet." : "No files are tracked through LFS yet."}</span></div>
                {:else}
                  {#each status.patterns as item (`${item.source}:${item.pattern}`)}
                    <article>
                      <div><code>{item.pattern}</code><span>{item.source}{item.lockable ? " · lockable" : ""}</span></div>
                      <button class="btn-sm danger" type="button" onclick={() => onUntrack(item.pattern)} disabled={isBusy || !canRemove(item)} title={canRemove(item) ? (isGerman ? "Muster entfernen" : "Remove pattern") : (isGerman ? "Nur Muster aus der Wurzel-.gitattributes können hier entfernt werden" : "Only patterns from the root .gitattributes can be removed here") }><Trash2 size={14} aria-hidden="true" /></button>
                    </article>
                  {/each}
                {/if}
              </div>
            </section>

            <section class="lfs-panel objects-panel">
              <header><div><span class="eyebrow">Current checkout</span><h3>{isGerman ? "LFS-Dateien" : "LFS files"}</h3></div><span>{status.files.length}</span></header>
              <div class="lfs-object-list">
                {#if status.files.length === 0}
                  <div class="lfs-empty"><HardDriveDownload size={20} aria-hidden="true" /><span>{isGerman ? "Im aktuellen Stand sind keine LFS-Objekte vorhanden." : "The current checkout has no LFS objects."}</span></div>
                {:else}
                  {#each status.files as file (`${file.oid}:${file.name}`)}
                    <article>
                      <span class:downloaded={file.downloaded} class="object-state" title={file.downloaded ? (isGerman ? "Objekt lokal vorhanden" : "Object available locally") : (isGerman ? "Nur LFS-Zeiger vorhanden" : "LFS pointer only")}>{#if file.downloaded}<Check size={12} />{:else}<Download size={12} />{/if}</span>
                      <div title={file.name}><strong>{file.name}</strong><span>{formatBytes(file.size)} · <code>{file.oid.slice(0, 10)}</code></span></div>
                    </article>
                  {/each}
                {/if}
              </div>
            </section>
          </div>
        {/if}
        </div>
      {/if}
    </div>

    <footer class="lfs-footer">
      <div><ShieldCheck size={14} aria-hidden="true" /><span>{isGerman ? ".gitattributes bleibt als normale Änderung sichtbar und muss committed werden." : ".gitattributes remains a normal change and must be committed."}</span></div>
      <div>
        <button class="btn-secondary" type="button" onclick={confirmPrune} disabled={isBusy || !status?.available}><Trash2 size={14} aria-hidden="true" />{isGerman ? "Cache bereinigen" : "Prune cache"}</button>
        <button class="btn-primary" type="button" onclick={onPull} disabled={isBusy || !setupReady}><HardDriveDownload size={15} aria-hidden="true" />{isGerman ? "Objekte laden" : "Pull objects"}</button>
      </div>
    </footer>
  </div>
</div>

<style>
  .lfs-dialog { --lfs-success: #4eca76; --lfs-warning: #f0b648; --lfs-danger: #e86060; width: min(880px, calc(100vw - 32px)); height: auto; max-height: min(660px, calc(100vh - 32px)); display: grid; grid-template-rows: auto minmax(0, 1fr) auto; overflow: hidden; border-radius: 12px; }
  .lfs-dialog-header, .lfs-heading, .dialog-header-actions, .lfs-footer, .lfs-footer > div { display: flex; align-items: center; }
  .lfs-dialog-header { min-height: 58px; justify-content: space-between; padding: 10px 13px; }
  .lfs-heading { gap: 9px; }
  .lfs-mark { display: grid; width: 34px; height: 34px; place-items: center; border: 1px solid color-mix(in srgb, var(--color-accent) 34%, var(--color-border)); border-radius: 9px; color: var(--color-accent); background: color-mix(in srgb, var(--color-accent) 10%, transparent); }
  .dialog-header-actions { gap: 7px; }
  .lfs-main { min-height: 0; overflow: hidden; }
  .lfs-error { display: flex; align-items: center; gap: 8px; margin: 10px 13px 0; padding: 8px 10px; border: 1px solid color-mix(in srgb, var(--lfs-danger) 38%, var(--color-border)); border-radius: 7px; color: var(--lfs-danger); background: color-mix(in srgb, var(--lfs-danger) 8%, transparent); font-size: 11px; }
  .lfs-loading { display: grid; min-height: 280px; place-items: center; align-content: center; gap: 10px; color: var(--color-ink-dim); font-size: 12px; }
  .lfs-content { min-height: 0; max-height: 548px; padding: 12px 13px 13px; overflow: auto; }
  .lfs-diagnostics { display: grid; grid-template-columns: minmax(0, 1fr) 22px minmax(0, 1fr) 22px minmax(0, 1fr); align-items: center; margin-bottom: 11px; }
  .lfs-diagnostics article { display: grid; grid-template-columns: auto minmax(0, 1fr); align-items: center; gap: 9px; min-height: 64px; padding: 8px 10px; border: 1px solid var(--color-border-subtle); border-radius: 8px; background: var(--color-surface-raised); }
  .lfs-diagnostics article.ready { border-color: color-mix(in srgb, var(--lfs-success) 34%, var(--color-border)); }
  .lfs-diagnostics article.warning { border-color: color-mix(in srgb, var(--lfs-warning) 38%, var(--color-border)); }
  .lfs-diagnostics article.error { border-color: color-mix(in srgb, var(--lfs-danger) 38%, var(--color-border)); }
  .diagnostic-icon { display: grid; width: 29px; height: 29px; place-items: center; border-radius: 8px; color: var(--color-ink-dim); background: var(--color-surface-hover); }
  article.ready .diagnostic-icon { color: var(--lfs-success); background: color-mix(in srgb, var(--lfs-success) 10%, transparent); }
  article.warning .diagnostic-icon { color: var(--lfs-warning); }
  article.error .diagnostic-icon { color: var(--lfs-danger); }
  .lfs-diagnostics article div { display: grid; min-width: 0; gap: 2px; }
  .lfs-diagnostics small { color: var(--color-ink-faint); font-size: 9px; font-weight: 800; letter-spacing: .08em; text-transform: uppercase; }
  .lfs-diagnostics strong { overflow: hidden; color: var(--color-ink); font-size: 12px; text-overflow: ellipsis; white-space: nowrap; }
  .lfs-diagnostics article div > span { color: var(--color-ink-dim); font-size: 10px; }
  .diagnostic-link { display: grid; place-items: center; color: var(--color-border); }
  .diagnostic-link.ready { color: color-mix(in srgb, var(--lfs-success) 60%, var(--color-border)); }
  .lfs-missing, .lfs-setup-card { display: flex; align-items: center; gap: 11px; padding: 12px; border: 1px solid var(--color-border-subtle); border-radius: 8px; background: var(--color-surface-raised); }
  .lfs-missing-icon { display: grid; flex: 0 0 auto; place-items: center; color: var(--lfs-danger); }
  .lfs-missing strong, .lfs-setup-card strong { color: var(--color-ink); font-size: 12px; }
  .lfs-missing p, .lfs-setup-card p { margin: 4px 0 0; color: var(--color-ink-dim); font-size: 10.5px; line-height: 1.5; }
  .lfs-setup-card { justify-content: space-between; margin-bottom: 11px; border-color: color-mix(in srgb, var(--lfs-warning) 32%, var(--color-border)); }
  .lfs-setup-card > div { max-width: 650px; }
  .lfs-setup-card button { flex: 0 0 auto; }
  .lfs-grid { display: grid; grid-template-columns: minmax(0, .92fr) minmax(0, 1.08fr); gap: 10px; height: clamp(230px, 30vh, 285px); min-height: 0; }
  .lfs-panel { display: grid; min-height: 0; grid-template-rows: auto auto minmax(0, 1fr); border: 1px solid var(--color-border-subtle); border-radius: 10px; overflow: hidden; background: var(--color-surface-raised); }
  .objects-panel { grid-template-rows: auto minmax(0, 1fr); }
  .lfs-panel > header { display: flex; align-items: center; justify-content: space-between; min-height: 48px; padding: 8px 10px; border-bottom: 1px solid var(--color-border-subtle); background: color-mix(in srgb, var(--app-dialog-chrome) 74%, transparent); }
  .lfs-panel h3 { margin: 2px 0 0; color: var(--color-ink); font-size: 13px; }
  .lfs-panel > header > span { display: grid; min-width: 25px; height: 22px; place-items: center; border-radius: 11px; color: var(--color-accent); background: color-mix(in srgb, var(--color-accent) 10%, transparent); font-size: 10px; font-weight: 800; }
  .lfs-track-form { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: 7px 9px; padding: 9px 10px; border-bottom: 1px solid var(--color-border-subtle); }
  .lfs-track-form > label:first-child { display: grid; gap: 5px; grid-column: 1 / -1; }
  .lfs-track-form label > span:first-child { color: var(--color-ink-dim); font-size: 9.5px; font-weight: 700; }
  .lfs-track-form input[type="text"] { width: 100%; }
  .lfs-lockable { display: inline-flex; width: fit-content; align-items: center; gap: 6px; cursor: pointer; user-select: none; }
  .lfs-lockable input[type="checkbox"] { width: 14px; min-width: 14px; height: 14px; margin: 0; padding: 0; border-radius: 3px; accent-color: var(--color-accent); cursor: pointer; box-shadow: none; }
  .lfs-lockable > span { display: flex; align-items: baseline; gap: 4px; white-space: nowrap; }
  .lfs-lockable strong { color: var(--color-ink); font-size: 10px; }
  .lfs-lockable small { color: var(--color-ink-faint); font-size: 8.5px; }
  .lfs-pattern-list, .lfs-object-list { min-height: 0; overflow: auto; }
  .lfs-pattern-list article, .lfs-object-list article { display: flex; align-items: center; gap: 9px; min-height: 49px; padding: 8px 10px; border-bottom: 1px solid var(--color-border-subtle); }
  .lfs-pattern-list article:last-child, .lfs-object-list article:last-child { border-bottom: 0; }
  .lfs-pattern-list article > div, .lfs-object-list article > div { display: grid; min-width: 0; flex: 1; gap: 3px; }
  .lfs-pattern-list code, .lfs-object-list strong { overflow: hidden; color: var(--color-ink); font-size: 10.5px; text-overflow: ellipsis; white-space: nowrap; }
  .lfs-pattern-list article span, .lfs-object-list article span { color: var(--color-ink-faint); font-size: 9px; }
  .object-state { display: grid; width: 24px; height: 24px; flex: 0 0 auto; place-items: center; border-radius: 50%; color: var(--lfs-warning); background: color-mix(in srgb, var(--lfs-warning) 10%, transparent); }
  .object-state.downloaded { color: var(--lfs-success); background: color-mix(in srgb, var(--lfs-success) 10%, transparent); }
  .lfs-empty { display: grid; width: 100%; height: 100%; min-height: 80px; place-items: center; align-content: center; gap: 7px; padding: 14px; color: var(--color-ink-faint); text-align: center; }
  .lfs-empty span { max-width: 260px; font-size: 10px; line-height: 1.45; }
  .lfs-footer { min-height: 54px; justify-content: space-between; gap: 14px; padding: 9px 13px; border-top: 1px solid var(--color-border-subtle); background: var(--app-dialog-chrome); }
  .lfs-footer > div { gap: 7px; }
  .lfs-footer > div:first-child { min-width: 0; color: var(--color-ink-dim); font-size: 9.5px; }
  .lfs-footer > div:last-child { flex: 0 0 auto; gap: 8px; }

  @media (max-width: 760px) {
    .dialog-backdrop { padding: 10px; }
    .lfs-dialog { width: min(620px, 100%); height: min(760px, 100%); max-height: none; }
    .lfs-content { height: 100%; max-height: none; }
    .lfs-diagnostics { grid-template-columns: 1fr; gap: 7px; }
    .diagnostic-link { display: none; }
    .lfs-grid { grid-template-columns: 1fr; height: auto; }
    .lfs-panel { min-height: 210px; }
    .lfs-footer { align-items: flex-start; flex-direction: column; }
    .lfs-footer > div:last-child { width: 100%; justify-content: flex-end; }
  }

  @media (max-width: 460px) {
    .lfs-dialog-header { min-height: 54px; }
    .lfs-mark { width: 31px; height: 31px; }
    .lfs-track-form { grid-template-columns: 1fr; }
    .lfs-track-form > label:first-child { grid-column: 1; }
    .lfs-track-form button { justify-self: end; }
    .lfs-lockable > span { white-space: normal; }
    .lfs-footer > div:first-child { display: none; }
    .lfs-footer > div:last-child { justify-content: stretch; }
    .lfs-footer button { flex: 1; }
  }
</style>
