<script lang="ts">
  import {
    Download,
    GitCommitHorizontal,
    Info,
    LoaderCircle,
    Save,
    StickyNote,
    Trash2,
    Upload,
    X,
  } from "@lucide/svelte";
  import type { AppLanguage, GitCommit, GitRemote } from "../types";
  import SelectMenu from "./SelectMenu.svelte";

  interface Props {
    commit: GitCommit;
    note: string;
    remotes: GitRemote[];
    preferredRemote: string;
    language: AppLanguage;
    isLoading: boolean;
    isBusy: boolean;
    error: string;
    status: string;
    onSave: (note: string) => void | Promise<void>;
    onDelete: () => void | Promise<void>;
    onFetch: (remote: string) => void | Promise<void>;
    onPush: (remote: string) => void | Promise<void>;
    onClose: () => void;
  }

  let {
    commit,
    note = "",
    remotes = [],
    preferredRemote = "",
    language = "en",
    isLoading = false,
    isBusy = false,
    error = "",
    status = "",
    onSave = () => {},
    onDelete = () => {},
    onFetch = () => {},
    onPush = () => {},
    onClose = () => {},
  }: Props = $props();

  let draft = $state("");
  let selectedRemote = $state("");
  let deleteConfirmOpen = $state(false);
  let lastLoadedKey = $state("");
  let hasChanges = $derived(draft !== note);
  let canSave = $derived(!isLoading && !isBusy && draft.trim().length > 0 && hasChanges);

  const text = $derived(language === "de" ? {
    eyebrow: "Interne Git-Notiz",
    title: "Commit-Notiz",
    commit: "Commit",
    explanation: "Die Notiz wird separat unter refs/notes/commits gespeichert. Hash und Commit-Historie bleiben unverändert.",
    label: "Notiz",
    placeholder: "Zum Beispiel Review-Hinweise, Ticket-Kontext, Build-ID oder Freigabestatus …",
    loading: "Notiz wird geladen …",
    syncTitle: "Mit Remote synchronisieren",
    syncHelp: "Git Notes reisen nicht automatisch mit Branches. Lade sie gezielt vom Remote oder sende deine lokalen Notizen dorthin.",
    noRemotes: "Für dieses Repository ist kein Remote eingerichtet.",
    remote: "Remote",
    fetch: "Vom Remote laden",
    push: "Zum Remote senden",
    delete: "Notiz löschen",
    deleteQuestion: "Diese Notiz wirklich löschen?",
    deleteConfirm: "Ja, löschen",
    cancel: "Abbrechen",
    close: "Schließen",
    save: "Notiz speichern",
    characters: "Zeichen",
  } : {
    eyebrow: "Internal Git note",
    title: "Commit note",
    commit: "Commit",
    explanation: "The note is stored separately under refs/notes/commits. The commit hash and history stay unchanged.",
    label: "Note",
    placeholder: "For example review findings, ticket context, a build ID, or approval status…",
    loading: "Loading note…",
    syncTitle: "Sync with a remote",
    syncHelp: "Git Notes do not travel with branches automatically. Fetch them explicitly from a remote or push your local notes there.",
    noRemotes: "No remote is configured for this repository.",
    remote: "Remote",
    fetch: "Fetch from remote",
    push: "Push to remote",
    delete: "Delete note",
    deleteQuestion: "Delete this note?",
    deleteConfirm: "Yes, delete",
    cancel: "Cancel",
    close: "Close",
    save: "Save note",
    characters: "characters",
  });

  $effect(() => {
    const loadedKey = `${commit.hash}:${note}`;
    if (loadedKey === lastLoadedKey) return;
    draft = note;
    lastLoadedKey = loadedKey;
    deleteConfirmOpen = false;
  });

  $effect(() => {
    if (selectedRemote && remotes.some((remote) => remote.name === selectedRemote)) return;
    selectedRemote = remotes.some((remote) => remote.name === preferredRemote)
      ? preferredRemote
      : (remotes[0]?.name ?? "");
  });

  function submit(event: SubmitEvent) {
    event.preventDefault();
    if (!canSave) return;
    void onSave(draft);
  }

  function handleKeydown(event: KeyboardEvent) {
    if (event.key === "Escape" && !isBusy) onClose();
    if ((event.ctrlKey || event.metaKey) && event.key.toLowerCase() === "s") {
      event.preventDefault();
      if (canSave) void onSave(draft);
    }
  }
</script>

<svelte:window onkeydown={handleKeydown} />

<div class="dialog-backdrop app-chrome-backdrop commit-note-backdrop" role="presentation">
  <div class="commit-note-dialog" role="dialog" aria-modal="true" aria-labelledby="commit-note-title" tabindex="-1">
    <header class="commit-note-head">
      <div class="commit-note-heading">
        <span class="commit-note-icon"><StickyNote size={20} aria-hidden="true" /></span>
        <div>
          <span class="eyebrow">{text.eyebrow}</span>
          <h2 id="commit-note-title">{text.title}</h2>
        </div>
      </div>
      <button class="dialog-close" type="button" onclick={onClose} disabled={isBusy} title={text.close} aria-label={text.close}>
        <X size={18} aria-hidden="true" />
      </button>
    </header>

    <div class="commit-note-body">
      <div class="commit-note-target">
        <span class="commit-target-icon"><GitCommitHorizontal size={18} aria-hidden="true" /></span>
        <div>
          <span>{text.commit} <code>{commit.short_hash}</code></span>
          <strong title={commit.summary}>{commit.summary}</strong>
          <small>{commit.author_name} · {new Date(commit.date).toLocaleString()}</small>
        </div>
      </div>

      <div class="commit-note-info">
        <Info size={16} aria-hidden="true" />
        <span>{text.explanation}</span>
      </div>

      {#if error}
        <div class="commit-note-message error" role="alert">{error}</div>
      {:else if status}
        <div class="commit-note-message success" role="status">{status}</div>
      {/if}

      <form class="commit-note-form" onsubmit={submit}>
        <label for="commit-note-editor">
          <span>{text.label}</span>
          <small>{draft.length.toLocaleString()} {text.characters}</small>
        </label>
        <div class="commit-note-editor-wrap">
          {#if isLoading}
            <div class="commit-note-loading"><LoaderCircle class="spin" size={18} aria-hidden="true" />{text.loading}</div>
          {/if}
          <!-- svelte-ignore a11y_autofocus -->
          <textarea
            id="commit-note-editor"
            bind:value={draft}
            placeholder={text.placeholder}
            disabled={isLoading || isBusy}
            maxlength={262144}
            spellcheck="true"
            autofocus
          ></textarea>
        </div>
      </form>

      <section class="commit-note-sync" aria-labelledby="commit-note-sync-title">
        <div class="commit-note-sync-copy">
          <strong id="commit-note-sync-title">{text.syncTitle}</strong>
          <span>{text.syncHelp}</span>
        </div>
        {#if remotes.length > 0}
          <div class="commit-note-sync-controls">
            <label>
              <span>{text.remote}</span>
              <SelectMenu value={selectedRemote} options={remotes.map((remote) => ({ value: remote.name, label: remote.name }))} disabled={isBusy} onChange={(value) => { selectedRemote = value; }} />
            </label>
            <button type="button" onclick={() => onFetch(selectedRemote)} disabled={isBusy || !selectedRemote || hasChanges}>
              {#if isBusy}<LoaderCircle class="spin" size={15} aria-hidden="true" />{:else}<Download size={15} aria-hidden="true" />{/if}
              {text.fetch}
            </button>
            <button type="button" onclick={() => onPush(selectedRemote)} disabled={isBusy || !selectedRemote || hasChanges}>
              {#if isBusy}<LoaderCircle class="spin" size={15} aria-hidden="true" />{:else}<Upload size={15} aria-hidden="true" />{/if}
              {text.push}
            </button>
          </div>
        {:else}
          <span class="commit-note-no-remotes">{text.noRemotes}</span>
        {/if}
      </section>
    </div>

    <footer class="commit-note-footer">
      <div class="commit-note-delete">
        {#if deleteConfirmOpen}
          <span>{text.deleteQuestion}</span>
          <button class="btn-danger" type="button" onclick={() => onDelete()} disabled={isBusy}>{text.deleteConfirm}</button>
          <button type="button" onclick={() => { deleteConfirmOpen = false; }} disabled={isBusy}>{text.cancel}</button>
        {:else}
          <button type="button" class="commit-note-delete-trigger" onclick={() => { deleteConfirmOpen = true; }} disabled={isBusy || isLoading || !note}>
            <Trash2 size={15} aria-hidden="true" />{text.delete}
          </button>
        {/if}
      </div>
      <div class="commit-note-actions">
        <button class="btn-secondary" type="button" onclick={onClose} disabled={isBusy}>{text.close}</button>
        <button class="btn-primary" type="button" onclick={() => onSave(draft)} disabled={!canSave}>
          {#if isBusy}<LoaderCircle class="spin" size={16} aria-hidden="true" />{:else}<Save size={16} aria-hidden="true" />{/if}
          {text.save}
        </button>
      </div>
    </footer>
  </div>
</div>

<style>
  .commit-note-backdrop { z-index: 72; }
  .commit-note-dialog {
    display: grid;
    grid-template-rows: auto minmax(0, 1fr) auto;
    width: min(720px, calc(100vw - 32px));
    max-height: min(780px, calc(100vh - 74px));
    overflow: hidden;
    border: 1px solid var(--color-border);
    border-radius: 14px;
    background: var(--app-dialog-bg);
    box-shadow: var(--app-dialog-shadow);
  }
  .commit-note-head,
  .commit-note-footer { display: flex; align-items: center; justify-content: space-between; gap: 14px; background: var(--app-dialog-chrome); }
  .commit-note-head { padding: 16px 18px; border-bottom: 1px solid var(--color-border-subtle); }
  .commit-note-heading { display: flex; align-items: center; gap: 12px; min-width: 0; }
  .commit-note-heading h2 { margin: 2px 0 0; color: var(--color-ink); font-size: 18px; line-height: 1.2; }
  .commit-note-icon,
  .commit-target-icon { display: grid; flex: 0 0 auto; place-items: center; color: var(--color-accent); background: color-mix(in srgb, var(--color-accent) 10%, transparent); }
  .commit-note-icon { width: 40px; height: 40px; border: 1px solid color-mix(in srgb, var(--color-accent) 28%, var(--color-border)); border-radius: 11px; }
  .commit-note-body { display: grid; align-content: start; gap: 13px; min-height: 0; padding: 16px 18px; overflow: auto; }
  .commit-note-target { display: grid; grid-template-columns: auto minmax(0, 1fr); align-items: center; gap: 11px; padding: 11px 12px; border: 1px solid var(--color-border-subtle); border-radius: 10px; background: var(--color-surface-raised); }
  .commit-target-icon { width: 34px; height: 34px; border-radius: 8px; }
  .commit-note-target > div { display: grid; gap: 3px; min-width: 0; }
  .commit-note-target span,
  .commit-note-target small { color: var(--color-ink-faint); font-size: 10.5px; }
  .commit-note-target code { margin-left: 4px; color: var(--color-accent); font: 700 10.5px var(--font-mono); }
  .commit-note-target strong { overflow: hidden; color: var(--color-ink); font-size: 13px; text-overflow: ellipsis; white-space: nowrap; }
  .commit-note-info { display: grid; grid-template-columns: auto minmax(0, 1fr); align-items: start; gap: 8px; padding: 10px 11px; border: 1px solid color-mix(in srgb, var(--color-accent) 22%, var(--color-border-subtle)); border-radius: 9px; color: var(--color-ink-muted); background: color-mix(in srgb, var(--color-accent) 6%, transparent); font-size: 11px; line-height: 1.45; }
  .commit-note-info :global(svg) { margin-top: 1px; color: var(--color-accent); }
  .commit-note-message { padding: 9px 11px; border: 1px solid; border-radius: 8px; font-size: 11px; font-weight: 700; }
  .commit-note-message.error { border-color: rgba(232, 96, 96, .32); color: #ef8888; background: rgba(232, 96, 96, .08); }
  .commit-note-message.success { border-color: color-mix(in srgb, #5bd18a 34%, var(--color-border)); color: #70dc99; background: color-mix(in srgb, #5bd18a 8%, transparent); }
  .commit-note-form { display: grid; gap: 6px; }
  .commit-note-form > label { display: flex; align-items: center; justify-content: space-between; gap: 10px; color: var(--color-ink-muted); font-size: 11px; font-weight: 800; }
  .commit-note-form > label small { color: var(--color-ink-faint); font-size: 9.5px; font-weight: 600; }
  .commit-note-editor-wrap { position: relative; }
  .commit-note-editor-wrap textarea { min-height: 164px; max-height: 320px; resize: vertical; font-size: 12.5px; line-height: 1.55; }
  .commit-note-loading { position: absolute; inset: 0; z-index: 1; display: flex; align-items: center; justify-content: center; gap: 8px; border-radius: 8px; color: var(--color-ink-muted); background: color-mix(in srgb, var(--app-input-bg) 92%, transparent); font-size: 11px; font-weight: 700; }
  .commit-note-sync { display: grid; gap: 11px; padding: 12px; border: 1px solid var(--color-border-subtle); border-radius: 10px; background: var(--color-surface-raised); }
  .commit-note-sync-copy { display: grid; gap: 4px; }
  .commit-note-sync-copy strong { color: var(--color-ink); font-size: 12px; }
  .commit-note-sync-copy span,
  .commit-note-no-remotes { color: var(--color-ink-faint); font-size: 10.5px; line-height: 1.45; }
  .commit-note-sync-controls { display: grid; grid-template-columns: minmax(130px, 1fr) auto auto; align-items: end; gap: 8px; }
  .commit-note-sync-controls label { display: grid; gap: 5px; color: var(--color-ink-muted); font-size: 10px; font-weight: 800; }
  .commit-note-sync-controls button { min-height: 34px; font-size: 10.5px; font-weight: 750; }
  .commit-note-footer { min-height: 66px; padding: 12px 18px; border-top: 1px solid var(--color-border-subtle); }
  .commit-note-delete,
  .commit-note-actions { display: flex; align-items: center; gap: 8px; }
  .commit-note-delete > span { color: var(--color-ink-muted); font-size: 10.5px; font-weight: 700; }
  .commit-note-delete-trigger { border-color: transparent; color: #e87a7a; background: transparent; }
  .commit-note-delete-trigger:hover:not(:disabled) { border-color: rgba(232, 96, 96, .24); color: #ff9a9a; background: rgba(232, 96, 96, .08); }
  @media (max-width: 660px) {
    .commit-note-sync-controls { grid-template-columns: 1fr; }
    .commit-note-footer { align-items: stretch; flex-direction: column; }
    .commit-note-delete,
    .commit-note-actions { justify-content: flex-end; }
  }
</style>
