<script setup lang="ts">
import type { IconName } from './UiIcon.vue'
import type { Tenant } from '~/types/tenant'
import type { Partner } from '~/types/partner'
import { FLAGS, INCIDENT } from '~/data/fixtures'

// Each row in the palette. `action` decides what happens on Enter / click.
// We try `to` first (a navigateTo) since most rows are navigation; `run` is
// the escape hatch for actions that aren't a route (open modal, toast, etc.).
interface Row {
  id: string
  groupLabel: string
  title: string
  subtitle?: string
  icon?: IconName
  badge?: string
  to?: string
  run?: () => void
}

const { isOpen, close } = useCommandPalette()
const { open: openImpersonation } = useImpersonation()
const { open: openIncident } = useIncidentModal()

const query = ref('')
const cursor = ref(0)
const inputRef = ref<HTMLInputElement | null>(null)

// Only fetch when the palette has been opened at least once, then refresh on
// every open so newly-created tenants/partners show up. SSR is disabled (the
// palette is client-only).
const { data: tenants, refresh: rT } = useLazyFetch<Tenant[]>('/api/tenants', { default: () => [], server: false })
const { data: partners, refresh: rP } = useLazyFetch<Partner[]>('/api/partners', { default: () => [], server: false })

const NAV: { id: string; label: string; icon: IconName; to: string }[] = [
  { id: 'n-overview', label: 'Overview',         icon: 'home',      to: '/' },
  { id: 'n-tenants',  label: 'Tenants',          icon: 'building',  to: '/tenants' },
  { id: 'n-partners', label: 'Partners',         icon: 'briefcase', to: '/partners' },
  { id: 'n-users',    label: 'Users (global)',   icon: 'users',     to: '/users' },
  { id: 'n-support',  label: 'Support',          icon: 'help',      to: '/support' },
  { id: 'n-billing',  label: 'Platform billing', icon: 'card',      to: '/billing' },
  { id: 'n-reports',  label: 'Reports',          icon: 'database',  to: '/reports' },
  { id: 'n-infra',    label: 'Infrastructure',   icon: 'plug',      to: '/infrastructure' },
  { id: 'n-flags',    label: 'Feature flags',    icon: 'shield',    to: '/flags' },
  { id: 'n-audit',    label: 'Audit log',        icon: 'file',      to: '/audit' },
  { id: 'n-team',     label: 'Operator team',    icon: 'users',     to: '/operator-team' },
  { id: 'n-settings', label: 'Platform settings',icon: 'shield',    to: '/settings' },
]

function tenantRows(): Row[] {
  return (tenants.value ?? []).map((t) => ({
    id: `t-${t._id}`,
    groupLabel: 'Tenants',
    title: t.name,
    subtitle: `${t.domains?.[0] ?? t.slug} · ${t.plan} · ${t.status}`,
    icon: 'building',
    badge: t.status,
    to: `/tenants/${t.slug}`,
  }))
}

function partnerRows(): Row[] {
  return (partners.value ?? []).map((p) => ({
    id: `p-${p._id}`,
    groupLabel: 'Partners',
    title: p.name,
    subtitle: `${p.domain} · ${p.customers} customers · ${p.marginPct}% margin`,
    icon: 'briefcase',
    badge: p.status,
    to: `/partners/${p.slug}`,
  }))
}

function flagRows(): Row[] {
  return FLAGS.slice(0, 6).map((f) => ({
    id: `f-${f.key}`,
    groupLabel: 'Feature flags',
    title: f.key,
    subtitle: f.state === 'rollout' ? `rollout · ${f.pct}% · ${f.scope}` : `${f.state} · ${f.scope}`,
    icon: 'plug',
    to: '/flags',
  }))
}

function navRows(): Row[] {
  return NAV.map((n) => ({
    id: n.id, groupLabel: 'Navigation', title: n.label, subtitle: 'navigate', icon: n.icon, to: n.to,
  }))
}

function actionRows(): Row[] {
  const firstTenant = tenants.value?.[0]
  return [
    {
      id: 'a-impersonate',
      groupLabel: 'Actions',
      title: 'Impersonate user…',
      subtitle: firstTenant ? `enter ${firstTenant.name} as a user` : 'no tenants yet',
      icon: 'key',
      run: () => firstTenant && openImpersonation(firstTenant),
    },
    {
      id: 'a-incident',
      groupLabel: 'Actions',
      title: 'Open active incident',
      subtitle: INCIDENT.title,
      icon: 'bell',
      run: () => openIncident(),
    },
    {
      id: 'a-toggle-theme',
      groupLabel: 'Actions',
      title: 'Toggle theme',
      subtitle: 'dark / light',
      icon: 'shield',
      run: () => {
        const { state, setTheme } = useTweaks()
        setTheme(state.value.theme === 'dark' ? 'light' : 'dark')
      },
    },
  ]
}

interface Group { label: string; items: Row[] }

const groups = computed<Group[]>(() => {
  const q = query.value.trim().toLowerCase()
  const all: Row[] = [
    ...tenantRows(),
    ...partnerRows(),
    ...flagRows(),
    ...navRows(),
    ...actionRows(),
  ]
  const matches = q
    ? all.filter((r) => r.title.toLowerCase().includes(q) || (r.subtitle ?? '').toLowerCase().includes(q))
    : all
  const grouped = new Map<string, Row[]>()
  for (const r of matches) {
    const arr = grouped.get(r.groupLabel) ?? []
    arr.push(r)
    grouped.set(r.groupLabel, arr)
  }
  // Stable group order
  const order = ['Tenants', 'Partners', 'Feature flags', 'Navigation', 'Actions']
  return order
    .filter((g) => grouped.has(g))
    .map((g) => ({ label: g, items: (grouped.get(g) ?? []).slice(0, 8) }))
})

const flat = computed(() => groups.value.flatMap((g) => g.items))

watch(isOpen, async (v) => {
  if (!v) return
  query.value = ''
  cursor.value = 0
  await Promise.all([rT(), rP()])
  await nextTick()
  inputRef.value?.focus()
})

watch(query, () => {
  cursor.value = 0
})

function activate(row?: Row) {
  if (!row) return
  if (row.run) row.run()
  if (row.to) navigateTo(row.to)
  close()
}

function onKey(e: KeyboardEvent) {
  if (e.key === 'Escape') {
    e.preventDefault()
    close()
  }
  if (e.key === 'ArrowDown') {
    e.preventDefault()
    cursor.value = Math.min(cursor.value + 1, Math.max(0, flat.value.length - 1))
  }
  if (e.key === 'ArrowUp') {
    e.preventDefault()
    cursor.value = Math.max(0, cursor.value - 1)
  }
  if (e.key === 'Enter') {
    e.preventDefault()
    activate(flat.value[cursor.value])
  }
}
</script>

<template>
  <Teleport to="body">
    <div v-if="isOpen" class="palette-backdrop" @click="close">
      <div class="palette" role="dialog" aria-label="Command palette" @click.stop>
        <div class="input-row">
          <UiIcon name="search" :size="14" />
          <input
            ref="inputRef"
            v-model="query"
            type="text"
            placeholder="Search tenants, partners, actions…"
            autocomplete="off"
            @keydown="onKey"
          />
          <span class="kbd">ESC</span>
        </div>

        <div class="results">
          <template v-if="groups.length">
            <div v-for="g in groups" :key="g.label" class="group">
              <div class="group-label">{{ g.label }}</div>
              <button
                v-for="item in g.items"
                :key="item.id"
                type="button"
                :class="['row', { active: item.id === flat[cursor]?.id }]"
                @mouseenter="cursor = flat.findIndex((x) => x.id === item.id)"
                @click="activate(item)"
              >
                <span class="icon-tile">
                  <UiIcon v-if="item.icon" :name="item.icon" :size="13" />
                </span>
                <span class="row-body">
                  <span class="row-title">{{ item.title }}</span>
                  <span v-if="item.subtitle" class="row-sub">{{ item.subtitle }}</span>
                </span>
                <Mono v-if="item.badge" dim>{{ item.badge }}</Mono>
              </button>
            </div>
          </template>
          <div v-else class="empty">
            <Mono dim>// no matches for "{{ query }}"</Mono>
          </div>
        </div>

        <footer>
          <Mono dim>{{ flat.length }} {{ flat.length === 1 ? 'result' : 'results' }}</Mono>
          <Mono dim>↑↓ navigate · ↵ open · esc close</Mono>
        </footer>
      </div>
    </div>
  </Teleport>
</template>

<style scoped>
.palette-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.55);
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding: 15vh 24px 24px 24px;
  z-index: 200;
}

.palette {
  width: 100%;
  max-width: 640px;
  background: var(--elevated);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 10px;
  box-shadow: 0 24px 80px rgba(0, 0, 0, 0.5);
  display: flex;
  flex-direction: column;
  max-height: 70vh;
  overflow: hidden;
}

.input-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 14px 18px;
  border-bottom: 1px solid var(--border);
  color: var(--text-mute);
}
.input-row input {
  flex: 1;
  border: 0;
  outline: 0;
  background: transparent;
  font-family: inherit;
  font-size: 15px;
  color: var(--text);
}
.kbd {
  font-family: var(--font-mono);
  font-size: 10px;
  padding: 2px 6px;
  background: var(--surface);
  border-radius: 3px;
  color: var(--text-mute);
  letter-spacing: 0.04em;
}

.results {
  flex: 1;
  overflow-y: auto;
  padding: 6px;
}
.group { margin-bottom: 4px; }
.group-label {
  padding: 10px 14px 4px 14px;
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  font-weight: 500;
  color: var(--text-mute);
}

.row {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  padding: 8px 14px;
  background: transparent;
  border: 0;
  border-left: 2px solid transparent;
  border-radius: 6px;
  color: var(--text);
  font-family: inherit;
  cursor: pointer;
  text-align: left;
}
.row.active {
  background: rgba(212, 255, 58, 0.08);
  border-left-color: var(--accent);
}
.icon-tile {
  width: 22px;
  height: 22px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--text-mute);
  flex-shrink: 0;
}
.row.active .icon-tile { color: var(--accent); }

.row-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.row-title { font-size: 13px; font-weight: 500; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.row-sub {
  font-size: 11px;
  color: var(--text-mute);
  font-family: var(--font-mono);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.empty { padding: 40px 18px; text-align: center; }

footer {
  padding: 8px 14px;
  border-top: 1px solid var(--border);
  display: flex;
  justify-content: space-between;
  align-items: center;
}
</style>
