<script setup lang="ts">
import { computed, nextTick, onMounted, ref, watch } from "vue";
import { useRouter } from "vue-router";
import { useSessionStore } from "../stores/session";
import { useTitlesStore } from "../stores/titles";
import { useUiStore } from "../stores/ui";
import BaseModal from "./BaseModal.vue";

const emit = defineEmits<{ (e: "close"): void }>();

const router = useRouter();
const session = useSessionStore();
const titles = useTitlesStore();
const ui = useUiStore();

const query = ref("");
const selected = ref(0);
const input = ref<HTMLInputElement | null>(null);

interface Row {
  id: string;
  label: string;
  hint: string;
  run: () => void;
}

function go(path: string) {
  void router.push(path);
  emit("close");
}
function compose() {
  void router.push("/").then(() => ui.requestCompose());
  emit("close");
}
function openNote(id: string) {
  void router.push({ path: "/", query: { open: id } });
  emit("close");
}

// Static command actions, filtered by query alongside note titles.
const commands = computed<Row[]>(() => {
  const list: Row[] = [
    { id: "cmd:new", label: "New note", hint: "Action", run: compose },
    { id: "cmd:board", label: "Go to Board", hint: "Navigate", run: () => go("/") },
    { id: "cmd:graph", label: "Go to Graph", hint: "Navigate", run: () => go("/graph") },
    { id: "cmd:reminders", label: "Go to Reminders", hint: "Navigate", run: () => go("/reminders") },
    { id: "cmd:timeline", label: "Go to Timeline", hint: "Navigate", run: () => go("/timeline") },
    { id: "cmd:archive", label: "Go to Archive", hint: "Navigate", run: () => go("/archive") },
    { id: "cmd:trash", label: "Go to Trash", hint: "Navigate", run: () => go("/trash") },
  ];
  if (session.user?.is_admin) {
    list.push({ id: "cmd:settings", label: "Open Settings", hint: "Navigate", run: () => go("/settings") });
  }
  return list;
});

const results = computed<Row[]>(() => {
  const q = query.value.trim().toLowerCase();
  const cmds = commands.value.filter((c) => !q || c.label.toLowerCase().includes(q));
  const notes: Row[] = titles.items
    .filter((t) => t.title && (!q || t.title.toLowerCase().includes(q)))
    .slice(0, q ? 12 : 6)
    .map((t) => ({ id: `note:${t.id}`, label: t.title, hint: "Note", run: () => openNote(t.id) }));
  // When searching text, surface matching notes first; when empty, lead with actions.
  return q ? [...notes, ...cmds] : [...cmds, ...notes];
});

watch(query, () => (selected.value = 0));

function activate() {
  results.value[selected.value]?.run();
}

function onKeydown(e: KeyboardEvent) {
  if (e.key === "ArrowDown") {
    e.preventDefault();
    selected.value = Math.min(selected.value + 1, results.value.length - 1);
  } else if (e.key === "ArrowUp") {
    e.preventDefault();
    selected.value = Math.max(selected.value - 1, 0);
  } else if (e.key === "Enter") {
    e.preventDefault();
    activate();
  } else if (e.key === "Escape") {
    e.preventDefault();
    emit("close");
  }
}

onMounted(async () => {
  await titles.load();
  await nextTick();
  input.value?.focus();
});
</script>

<template>
  <BaseModal
    panel-class="w-full max-w-lg overflow-hidden shadow-2xl"
    aria-label="Command palette"
    @close="emit('close')"
  >
      <input
        ref="input"
        v-model="query"
        type="text"
        placeholder="Jump to a note or run a command…"
        aria-label="Jump to a note or run a command"
        class="w-full border-b border-neutral-200 bg-transparent px-4 py-3 text-sm outline-none placeholder:text-neutral-400 dark:border-neutral-700"
        @keydown="onKeydown"
      />
      <ul v-if="results.length" class="max-h-80 overflow-y-auto py-1">
        <li v-for="(row, i) in results" :key="row.id">
          <button
            type="button"
            class="flex w-full items-center justify-between gap-3 px-4 py-2 text-left text-sm"
            :class="
              i === selected
                ? 'bg-brand/15 text-brand-700 dark:text-brand'
                : 'hover:bg-neutral-100 dark:hover:bg-neutral-800'
            "
            @mousemove="selected = i"
            @click="
              selected = i;
              activate();
            "
          >
            <span class="truncate">{{ row.label }}</span>
            <span class="shrink-0 text-xs text-neutral-400">{{ row.hint }}</span>
          </button>
        </li>
      </ul>
      <p v-else class="px-4 py-6 text-center text-sm text-neutral-400">No matches</p>
  </BaseModal>
</template>
