<script setup lang="ts">
import { ref, computed, onMounted } from "vue";
import { apiGet, pinNoteVersion, unpinNoteVersion } from "@/api/client";
import DiffView from "@/components/DiffView.vue";
import type { DiffLine } from "@/composables/useAssist";
import { fmtStamp } from "@/utils/dateFormat";

interface NoteVersion {
  id: number;
  note_id: number;
  title: string;
  tags: string[];
  body?: string;
  pin_kind: "auto" | "manual" | null;
  pin_label: string | null;
  created_at: string;
}

const props = defineProps<{
  noteId: number;
  currentBody: string;
}>();

const emit = defineEmits<{
  (e: 'restore', body: string, tags: string[]): void;
  (e: 'close'): void;
}>();

const versions = ref<NoteVersion[]>([]);
const selectedVersion = ref<NoteVersion | null>(null);
const loading = ref(false);
const loadingDetail = ref(false);

const diff = computed<DiffLine[]>(() => {
  if (!selectedVersion.value?.body) return [];
  const a = props.currentBody;
  const b = selectedVersion.value.body;

  const aLines = a.split('\n');
  const bLines = b.split('\n');
  const m = aLines.length, n = bLines.length;
  const dp: number[][] = Array.from({ length: m + 1 }, () => new Array(n + 1).fill(0));
  for (let i = m - 1; i >= 0; i--)
    for (let j = n - 1; j >= 0; j--)
      dp[i][j] = aLines[i] === bLines[j]
        ? dp[i+1][j+1] + 1
        : Math.max(dp[i+1][j], dp[i][j+1]);
  const result: DiffLine[] = [];
  let i = 0, j = 0;
  while (i < m && j < n) {
    if (aLines[i] === bLines[j]) { result.push({ type: 'equal', text: aLines[i++] }); j++; }
    else if (dp[i+1][j] >= dp[i][j+1]) result.push({ type: 'delete', text: aLines[i++] });
    else result.push({ type: 'insert', text: bLines[j++] });
  }
  while (i < m) result.push({ type: 'delete', text: aLines[i++] });
  while (j < n) result.push({ type: 'insert', text: bLines[j++] });
  return result;
});

async function loadVersions() {
  loading.value = true;
  try {
    const data = await apiGet<{ versions: NoteVersion[] }>(
      `/api/notes/${props.noteId}/versions`
    );
    versions.value = data.versions;
    if (versions.value.length > 0) {
      await selectVersionItem(versions.value[0]);
    }
  } catch {
    // silent
  } finally {
    loading.value = false;
  }
}

async function selectVersionItem(v: NoteVersion) {
  if (v.body !== undefined) {
    selectedVersion.value = v;
    return;
  }
  loadingDetail.value = true;
  try {
    const full = await apiGet<NoteVersion>(
      `/api/notes/${props.noteId}/versions/${v.id}`
    );
    // Cache body back onto list item
    const listItem = versions.value.find(x => x.id === v.id);
    if (listItem) listItem.body = full.body;
    selectedVersion.value = full;
  } catch {
    // silent
  } finally {
    loadingDetail.value = false;
  }
}

function restore() {
  if (!selectedVersion.value?.body) return;
  emit('restore', selectedVersion.value.body, selectedVersion.value.tags ?? []);
}

// ── Pin / unpin / edit-label state ──────────────────────────────────────────

const editingLabel = ref(false);
const draftLabel = ref("");
const pinSaving = ref(false);

function startEditLabel() {
  if (!selectedVersion.value) return;
  draftLabel.value = selectedVersion.value.pin_label ?? "";
  editingLabel.value = true;
}

function cancelEditLabel() {
  editingLabel.value = false;
  draftLabel.value = "";
}

async function savePin() {
  if (!selectedVersion.value || pinSaving.value) return;
  pinSaving.value = true;
  try {
    const updated = await pinNoteVersion(
      props.noteId, selectedVersion.value.id, draftLabel.value || null,
    );
    // Reflect server state in the local list + selected version.
    const idx = versions.value.findIndex(v => v.id === updated.id);
    if (idx >= 0) {
      versions.value[idx].pin_kind = updated.pin_kind;
      versions.value[idx].pin_label = updated.pin_label;
    }
    if (selectedVersion.value) {
      selectedVersion.value.pin_kind = updated.pin_kind;
      selectedVersion.value.pin_label = updated.pin_label;
    }
    editingLabel.value = false;
  } catch {
    // silent — leaving the form open lets the user retry
  } finally {
    pinSaving.value = false;
  }
}

async function unpinSelected() {
  if (!selectedVersion.value || pinSaving.value) return;
  pinSaving.value = true;
  try {
    await unpinNoteVersion(props.noteId, selectedVersion.value.id);
    const idx = versions.value.findIndex(v => v.id === selectedVersion.value!.id);
    if (idx >= 0) {
      versions.value[idx].pin_kind = null;
      versions.value[idx].pin_label = null;
    }
    if (selectedVersion.value) {
      selectedVersion.value.pin_kind = null;
      selectedVersion.value.pin_label = null;
    }
  } catch {
    // silent
  } finally {
    pinSaving.value = false;
  }
}

onMounted(loadVersions);
</script>

<template>
  <teleport to="body">
    <div class="modal-overlay" @click.self="emit('close')">
      <div class="modal-card history-modal">
        <div class="history-header">
          <h3 class="history-title">Version History</h3>
          <button class="history-close" aria-label="Close version history" @click="emit('close')">&times;</button>
        </div>

        <div class="history-body">
          <!-- Left: version list -->
          <div class="history-list">
            <div v-if="loading" class="history-empty">Loading...</div>
            <div v-else-if="!versions.length" class="history-empty">No versions yet.</div>
            <div
              v-for="v in versions"
              :key="v.id"
              :class="['history-item', { selected: selectedVersion?.id === v.id }]"
              @click="selectVersionItem(v)"
            >
              <div class="history-item-title">
                <span
                  v-if="v.pin_kind === 'manual'"
                  class="pin-badge pin-badge-manual"
                  :title="v.pin_label || 'Pinned'"
                  aria-label="manually pinned"
                >●</span>
                <span
                  v-else-if="v.pin_kind === 'auto'"
                  class="pin-badge pin-badge-auto"
                  :title="v.pin_label || 'Auto-pinned (stable)'"
                  aria-label="auto-pinned"
                >◐</span>
                {{ v.title || 'Untitled' }}
              </div>
              <div
                v-if="v.pin_kind === 'manual' && v.pin_label"
                class="history-item-label"
              >{{ v.pin_label }}</div>
              <div class="history-item-date">{{ fmtStamp(v.created_at) }}</div>
            </div>
          </div>

          <!-- Right: diff -->
          <div class="history-diff">
            <div v-if="loadingDetail" class="history-empty">Loading version...</div>
            <div v-else-if="!selectedVersion" class="history-empty">Select a version to compare.</div>
            <template v-else>
              <div class="version-pin-controls">
                <!-- Label editor -->
                <div v-if="editingLabel" class="pin-label-form">
                  <input
                    v-model="draftLabel"
                    maxlength="500"
                    type="text"
                    class="pin-label-input"
                    placeholder="Optional label (e.g. 'post-network-refresh runbook')"
                  />
                  <button class="btn-pin-save" :disabled="pinSaving" @click="savePin">
                    {{ pinSaving ? "Saving…" : "Save" }}
                  </button>
                  <button class="btn-pin-cancel" @click="cancelEditLabel">Cancel</button>
                </div>

                <!-- Default: kind-aware action row -->
                <div v-else class="pin-actions">
                  <span v-if="selectedVersion.pin_kind === 'manual'" class="pin-state">
                    <span class="pin-badge pin-badge-manual">●</span>
                    Manually pinned{{ selectedVersion.pin_label ? `: ${selectedVersion.pin_label}` : '' }}
                  </span>
                  <span v-else-if="selectedVersion.pin_kind === 'auto'" class="pin-state">
                    <span class="pin-badge pin-badge-auto">◐</span>
                    Auto-pinned{{ selectedVersion.pin_label ? `: ${selectedVersion.pin_label}` : '' }}
                  </span>

                  <button
                    v-if="selectedVersion.pin_kind === null"
                    class="btn-pin"
                    :disabled="pinSaving"
                    @click="startEditLabel"
                  >Pin version</button>
                  <button
                    v-else-if="selectedVersion.pin_kind === 'manual'"
                    class="btn-pin-edit"
                    :disabled="pinSaving"
                    @click="startEditLabel"
                  >Edit label</button>
                  <button
                    v-else
                    class="btn-pin"
                    :disabled="pinSaving"
                    @click="startEditLabel"
                  >Pin permanently</button>
                  <button
                    v-if="selectedVersion.pin_kind === 'manual'"
                    class="btn-unpin"
                    :disabled="pinSaving"
                    @click="unpinSelected"
                  >Unpin</button>
                </div>
              </div>
              <DiffView :diff="diff" />
            </template>
          </div>
        </div>

        <div class="history-footer">
          <button
            class="btn-primary"
            :disabled="!selectedVersion?.body"
            @click="restore"
          >Restore this version</button>
          <button class="modal-btn" @click="emit('close')">Close</button>
        </div>
      </div>
    </div>
  </teleport>
</template>

<style scoped>
.history-modal {
  max-width: 900px;
  width: 95%;
  height: 80vh;
  max-height: 700px;
  display: flex;
  flex-direction: column;
  padding: 0;
}

.history-header {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.9rem 1.25rem;
  border-bottom: 1px solid var(--fs-border-color);
}

.history-title {
  margin: 0;
  font-size: 1rem;
}

.history-close {
  background: none;
  border: none;
  font-size: 1.25rem;
  cursor: pointer;
  color: var(--fs-text-tertiary);
  line-height: 1;
  padding: 0.1rem 0.3rem;
}
.history-close:hover { color: var(--fs-text-primary); }

.history-body {
  flex: 1;
  min-height: 0;
  display: flex;
  overflow: hidden;
}

.history-list {
  width: 220px;
  flex-shrink: 0;
  border-right: 1px solid var(--fs-border-color);
  overflow-y: auto;
}

.history-item {
  padding: 0.6rem 0.9rem;
  cursor: pointer;
  border-left: 3px solid transparent;
  border-bottom: 1px solid var(--fs-border-color);
}
.history-item:hover { background: var(--fs-surface-raised); }
.history-item.selected {
  border-left-color: var(--fs-accent);
  background: var(--fs-surface-raised);
}

.history-item-title {
  font-size: 0.85rem;
  font-weight: 500;
  color: var(--fs-text-primary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.history-item-date {
  font-size: 0.75rem;
  color: var(--fs-text-tertiary);
  margin-top: 0.15rem;
}

.history-diff {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  padding: 0.5rem;
}

.history-empty {
  padding: 1rem;
  font-size: 0.85rem;
  color: var(--fs-text-tertiary);
}

.history-footer {
  flex-shrink: 0;
  display: flex;
  gap: 0.5rem;
  justify-content: flex-end;
  padding: 0.75rem 1.25rem;
  border-top: 1px solid var(--fs-border-color);
}


/* ── Pin badges + label rendering ───────────────────────────────────────── */
.pin-badge {
  display: inline-block;
  width: 0.7rem;
  text-align: center;
  margin-right: 0.35rem;
  font-size: 0.85em;
  line-height: 1;
}
.pin-badge-manual { color: var(--fs-accent); }
.pin-badge-auto { color: var(--fs-text-tertiary); }

.history-item-label {
  font-size: 0.72rem;
  color: var(--fs-accent);
  font-style: italic;
  margin-top: 0.15rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ── Pin controls above the diff ────────────────────────────────────────── */
.version-pin-controls {
  padding: 0.4rem 0.5rem 0.5rem;
  border-bottom: 1px solid var(--fs-border-color);
  font-size: 0.82rem;
}
.pin-actions {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-wrap: wrap;
}
.pin-state {
  font-style: italic;
  color: var(--fs-text-tertiary);
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.btn-pin, .btn-pin-edit, .btn-unpin {
  padding: 0.25rem 0.7rem;
  font-size: 0.78rem;
  background: transparent;
  color: inherit;
  border: 1px solid var(--fs-border-color);
  border-radius: 999px;
  cursor: pointer;
}
.btn-pin:hover:not(:disabled), .btn-pin-edit:hover:not(:disabled) {
  background: rgba(99, 102, 241, 0.12);
  border-color: var(--fs-accent);
}
.btn-unpin:hover:not(:disabled) {
  background: rgba(239, 68, 68, 0.10);
  border-color: rgba(239, 68, 68, 0.5);
}
.pin-label-form {
  display: flex;
  gap: 0.4rem;
  align-items: center;
}
.pin-label-input {
  flex: 1;
  padding: 0.3rem 0.5rem;
  font-size: 0.85rem;
  background: var(--fs-surface-page);
  border: 1px solid var(--fs-border-color);
  border-radius: var(--fs-radius-sm);
  color: inherit;
}
.pin-label-input:focus {
  outline: none;
  border-color: var(--fs-accent);
}
.btn-pin-save, .btn-pin-cancel {
  padding: 0.3rem 0.7rem;
  font-size: 0.78rem;
  background: transparent;
  color: inherit;
  border: 1px solid var(--fs-border-color);
  border-radius: var(--fs-radius-sm);
  cursor: pointer;
}
.btn-pin-save:hover:not(:disabled) {
  background: rgba(99, 102, 241, 0.12);
  border-color: var(--fs-accent);
}
.btn-pin-save:disabled, .btn-pin-cancel:disabled,
.btn-pin:disabled, .btn-pin-edit:disabled, .btn-unpin:disabled {
  opacity: 0.5;
  cursor: progress;
}
</style>
