<script setup lang="ts">
import {
  Activity,
  Bot,
  Boxes,
  FileText,
  LayoutDashboard,
  ListTodo,
  Play,
  Search,
  Settings,
  Shield,
  Sparkles,
  Workflow,
} from '@lucide/vue'
import { computed, nextTick, ref, watch } from 'vue'
import { useRouter } from 'vue-router'
import { useOpenClawOverviewQuery } from '../../api/openclawRuntime'
import { useProjects } from '../../api/projects'
import { useTaskBoard } from '../../api/taskBoard'
import type { MissionControlContext } from '../../types/mission-control'

interface CommandEntry {
  id: string
  label: string
  description: string
  group: 'Actions' | 'Navigation' | 'Objects'
  icon: unknown
  route?: string | { path: string; query?: Record<string, string> }
  keywords: string
  action?: 'iris'
}

const props = defineProps<{
  open: boolean
  context: MissionControlContext
  canOpenIris: boolean
  canStartRun: boolean
}>()

const emit = defineEmits<{
  close: []
  askIris: []
}>()

const router = useRouter()
const overviewQuery = useOpenClawOverviewQuery()
const projects = useProjects()
const taskBoard = useTaskBoard(50)
const dialogEl = ref<HTMLDialogElement | null>(null)
const inputEl = ref<HTMLInputElement | null>(null)
const query = ref('')
const activeIndex = ref(0)

const navigationCommands: CommandEntry[] = [
  { id: 'nav-dashboard', label: 'Dashboard', description: 'Live orchestration workspace', group: 'Navigation', icon: LayoutDashboard, route: '/dashboard', keywords: 'home overview orchestration' },
  { id: 'nav-runs', label: 'Run Control', description: 'Runs, sessions and approvals', group: 'Navigation', icon: Workflow, route: '/runs', keywords: 'openclaw sessions approvals tasks' },
  { id: 'nav-tasks', label: 'Task Board', description: 'Nexus work queue', group: 'Navigation', icon: ListTodo, route: '/tasks', keywords: 'board work items' },
  { id: 'nav-agents', label: 'Agents', description: 'OpenClaw agent inventory', group: 'Navigation', icon: Bot, route: '/agents', keywords: 'workers openclaw' },
  { id: 'nav-projects', label: 'Projects', description: 'Mission scopes and delivery', group: 'Navigation', icon: Boxes, route: '/projects', keywords: 'workspaces delivery' },
  { id: 'nav-activity', label: 'Activity', description: 'Operational audit trail', group: 'Navigation', icon: Activity, route: '/activity', keywords: 'events audit logs' },
  { id: 'nav-docs', label: 'Docs', description: 'Operational knowledge', group: 'Navigation', icon: FileText, route: '/docs', keywords: 'documentation knowledge' },
  { id: 'nav-security', label: 'Security', description: 'Trust and approval controls', group: 'Navigation', icon: Shield, route: '/security', keywords: 'auth approvals governance' },
  { id: 'nav-settings', label: 'Settings', description: 'Nexus and OpenClaw configuration', group: 'Navigation', icon: Settings, route: '/settings', keywords: 'configuration gateway' },
]

const allCommands = computed<CommandEntry[]>(() => {
  const contextLabel = props.context.entityType && props.context.entityId
    ? `${props.context.entityType} ${props.context.entityId}`
    : props.context.surface

  const entries: CommandEntry[] = []
  if (props.canOpenIris) {
    entries.push({
      id: 'action-iris',
      label: `Ask Iris about ${contextLabel}`,
      description: `Send the current ${props.context.surface} context with your request`,
      group: 'Actions',
      icon: Sparkles,
      action: 'iris',
      keywords: `assistant iris ask ${props.context.routeName} ${props.context.entityId ?? ''}`,
    })
  }
  if (props.canStartRun) {
    entries.push({
      id: 'action-start-run',
      label: props.context.entityType && props.context.entityId
        ? `Start run for this ${props.context.entityType}`
        : 'Start OpenClaw run',
      description: 'Dispatch a durable, correlated agent run',
      group: 'Actions',
      icon: Play,
      route: {
        path: '/runs',
        query: {
          new: '1',
          ...(props.context.entityType === 'task' && props.context.entityId
            ? { taskId: props.context.entityId }
            : {}),
          ...(props.context.entityType === 'project' && props.context.entityId
            ? { projectId: props.context.entityId }
            : {}),
          ...(props.context.entityType === 'agent' && props.context.entityId
            ? { agentId: props.context.entityId }
            : {}),
        },
      },
      keywords: `start dispatch durable run ${props.context.entityType ?? ''} ${props.context.entityId ?? ''}`,
    })
  }
  entries.push(...navigationCommands)

  for (const project of projects.query.data.value ?? []) {
    entries.push({
      id: `project-${project.id}`,
      label: project.name,
      description: `Project · ${project.status}`,
      group: 'Objects',
      icon: Boxes,
      route: `/projects/${encodeURIComponent(project.id)}`,
      keywords: `project ${project.status}`,
    })
  }

  const tasks = [
    ...taskBoard.board.value.offen,
    ...taskBoard.board.value.inProgress,
    ...taskBoard.board.value.review,
    ...taskBoard.board.value.blocked,
    ...taskBoard.board.value.done,
  ]
  for (const task of tasks) {
    entries.push({
      id: `task-${task.id}`,
      label: task.title,
      description: `Task · ${task.state} · ${task.priority}`,
      group: 'Objects',
      icon: ListTodo,
      route: `/tasks/${encodeURIComponent(task.id)}`,
      keywords: `task ${task.state} ${task.priority}`,
    })
  }

  for (const agent of overviewQuery.data.value?.agents.items ?? []) {
    entries.push({
      id: `agent-${agent.id}`,
      label: agent.name,
      description: `Agent · ${agent.status}${agent.model ? ` · ${agent.model}` : ''}`,
      group: 'Objects',
      icon: Bot,
      route: `/agents/${encodeURIComponent(agent.id)}`,
      keywords: `agent ${agent.id} ${agent.status} ${agent.model ?? ''}`,
    })
  }

  for (const session of overviewQuery.data.value?.sessions.items ?? []) {
    entries.push({
      id: `session-${session.key}`,
      label: session.title,
      description: `Session · ${session.status} · ${session.agentId}`,
      group: 'Objects',
      icon: Workflow,
      route: { path: '/runs', query: { session: session.key } },
      keywords: `session run ${session.key} ${session.agentId} ${session.status}`,
    })
  }

  return entries
})

const filteredCommands = computed(() => {
  const terms = query.value
    .trim()
    .toLocaleLowerCase()
    .split(/\s+/)
    .filter(Boolean)

  const matches = terms.length
    ? allCommands.value.filter(command => {
        const haystack = `${command.label} ${command.description} ${command.keywords}`.toLocaleLowerCase()
        return terms.every(term => haystack.includes(term))
      })
    : allCommands.value

  return matches.slice(0, 14)
})

const groupedCommands = computed(() => {
  const groups: Array<{ label: CommandEntry['group']; items: CommandEntry[] }> = []
  for (const label of ['Actions', 'Navigation', 'Objects'] as const) {
    const items = filteredCommands.value.filter(command => command.group === label)
    if (items.length) groups.push({ label, items })
  }
  return groups
})

watch(
  () => props.open,
  async isOpen => {
    if (isOpen) {
      query.value = ''
      activeIndex.value = 0
      if (dialogEl.value && !dialogEl.value.open) dialogEl.value.showModal()
      await nextTick()
      inputEl.value?.focus()
    } else if (dialogEl.value?.open) {
      dialogEl.value.close()
    }
  },
  { immediate: true },
)

watch(filteredCommands, items => {
  if (!items.length) activeIndex.value = 0
  else activeIndex.value = Math.min(activeIndex.value, items.length - 1)
})

function closeDialog() {
  dialogEl.value?.close()
}

function onDialogClose() {
  emit('close')
}

function onBackdropClick(event: MouseEvent) {
  if (event.target === event.currentTarget) closeDialog()
}

async function execute(command: CommandEntry) {
  if (command.action === 'iris') {
    if (!props.canOpenIris) return
    emit('askIris')
    return
  }

  if (command.id === 'action-start-run' && !props.canStartRun) return

  if (command.route) {
    await router.push(command.route)
    emit('close')
  }
}

function onKeydown(event: KeyboardEvent) {
  if (event.key === 'Escape') {
    event.preventDefault()
    closeDialog()
  } else if (event.key === 'ArrowDown') {
    event.preventDefault()
    if (filteredCommands.value.length) {
      activeIndex.value = (activeIndex.value + 1) % filteredCommands.value.length
    }
  } else if (event.key === 'ArrowUp') {
    event.preventDefault()
    if (filteredCommands.value.length) {
      activeIndex.value = (activeIndex.value - 1 + filteredCommands.value.length) % filteredCommands.value.length
    }
  } else if (event.key === 'Enter') {
    event.preventDefault()
    const command = filteredCommands.value[activeIndex.value]
    if (command) void execute(command)
  }
}

function flatIndex(command: CommandEntry) {
  return filteredCommands.value.findIndex(item => item.id === command.id)
}
</script>

<template>
  <dialog
    id="mission-command-dialog"
    ref="dialogEl"
    class="command-dialog"
    aria-labelledby="command-dialog-title"
    @click="onBackdropClick"
    @cancel.prevent="closeDialog"
    @close="onDialogClose"
  >
    <section class="command-panel">
      <h2 id="command-dialog-title" class="sr-only">Mission Control commands</h2>
      <label class="command-search">
        <Search :size="18" aria-hidden="true" />
        <input
          ref="inputEl"
          v-model="query"
          type="search"
          placeholder="Operationen, Agents, Tasks oder Projekte suchen…"
          autocomplete="off"
          aria-label="Mission Control durchsuchen"
          :aria-activedescendant="filteredCommands[activeIndex] ? `command-${filteredCommands[activeIndex].id}` : undefined"
          @keydown="onKeydown"
        />
        <kbd>Esc</kbd>
      </label>

      <div class="command-results" role="listbox" aria-label="Commands">
        <div v-if="!filteredCommands.length" class="command-empty">
          Keine passende Operation gefunden.
        </div>
        <section v-for="group in groupedCommands" :key="group.label" class="command-group">
          <h3>{{ group.label }}</h3>
          <button
            v-for="command in group.items"
            :id="`command-${command.id}`"
            :key="command.id"
            type="button"
            class="command-row"
            :class="{ active: flatIndex(command) === activeIndex }"
            role="option"
            :aria-selected="flatIndex(command) === activeIndex"
            @mouseenter="activeIndex = flatIndex(command)"
            @click="execute(command)"
          >
            <span class="command-icon" aria-hidden="true">
              <component :is="command.icon" :size="17" />
            </span>
            <span class="command-copy">
              <strong>{{ command.label }}</strong>
              <small>{{ command.description }}</small>
            </span>
            <span class="command-enter" aria-hidden="true">↵</span>
          </button>
        </section>
      </div>

      <footer class="command-footer">
        <span><kbd>↑</kbd><kbd>↓</kbd> auswählen</span>
        <span><kbd>↵</kbd> öffnen</span>
        <span class="command-context">{{ context.surface }}<template v-if="context.entityId"> · {{ context.entityId }}</template></span>
      </footer>
    </section>
  </dialog>
</template>

<style scoped>
.command-dialog {
  width: min(720px, calc(100vw - 32px));
  max-width: none;
  max-height: min(760px, calc(100dvh - 48px));
  margin: 11vh auto auto;
  padding: 0;
  overflow: visible;
  border: 0;
  background: transparent;
  color: var(--tx);
}

.command-dialog::backdrop {
  background: color-mix(in srgb, var(--space-0) 78%, transparent);
  backdrop-filter: blur(14px);
}

.command-panel {
  overflow: hidden;
  border: 1px solid var(--line-3);
  border-radius: var(--r-lg);
  background: linear-gradient(160deg, rgba(22, 18, 50, .98), rgba(10, 8, 28, .98));
  box-shadow: var(--panel-shadow), 0 0 58px -16px rgba(124, 108, 255, .38);
  backdrop-filter: blur(18px);
}

.command-search {
  min-height: 62px;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: 12px;
  padding: 0 18px;
  border-bottom: 1px solid var(--line);
  color: var(--tx-3);
}

.command-search input {
  min-width: 0;
  height: 60px;
  border: 0;
  outline: 0;
  background: transparent;
  color: var(--tx);
  font-family: var(--font-body);
  font-size: 15px;
}

.command-search input::placeholder {
  color: var(--tx-3);
}

kbd {
  min-width: 24px;
  min-height: 22px;
  display: inline-grid;
  place-items: center;
  padding: 2px 6px;
  border: 1px solid var(--line-2);
  border-radius: 6px;
  background: var(--accent-wash);
  color: var(--tx-3);
  font-family: var(--font-mono-v2);
  font-size: 10px;
}

.command-results {
  max-height: min(560px, calc(100dvh - 220px));
  overflow-y: auto;
  padding: 10px;
  scrollbar-width: thin;
  scrollbar-color: var(--accent-scroll) transparent;
}

.command-group + .command-group {
  margin-top: 8px;
}

.command-group h3 {
  margin: 0;
  padding: 7px 9px 5px;
  color: var(--tx-3);
  font-family: var(--font-mono-v2);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .13em;
  text-transform: uppercase;
}

.command-row {
  width: 100%;
  min-height: 54px;
  display: grid;
  grid-template-columns: 36px minmax(0, 1fr) auto;
  align-items: center;
  gap: 11px;
  padding: 7px 10px;
  border: 1px solid transparent;
  border-radius: var(--r-sm);
  background: transparent;
  color: var(--tx);
  text-align: left;
  cursor: pointer;
}

.command-row.active {
  border-color: var(--line-2);
  background: var(--grad-soft);
}

.command-icon {
  width: 34px;
  height: 34px;
  display: grid;
  place-items: center;
  border: 1px solid var(--line);
  border-radius: 9px;
  background: var(--accent-wash);
  color: var(--a-mid);
}

.command-copy {
  min-width: 0;
  display: grid;
  gap: 2px;
}

.command-copy strong {
  overflow: hidden;
  color: var(--tx);
  font-family: var(--font-body);
  font-size: 12.5px;
  font-weight: 700;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.command-copy small {
  overflow: hidden;
  color: var(--tx-3);
  font-family: var(--font-body);
  font-size: 11px;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.command-enter {
  color: var(--tx-3);
  font-family: var(--font-mono-v2);
  font-size: 13px;
  opacity: 0;
}

.command-row.active .command-enter {
  opacity: 1;
}

.command-empty {
  padding: 36px 16px;
  color: var(--tx-3);
  font-size: 12px;
  text-align: center;
}

.command-footer {
  min-height: 40px;
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 8px 12px;
  border-top: 1px solid var(--line);
  color: var(--tx-3);
  font-size: 10px;
}

.command-footer span {
  display: inline-flex;
  align-items: center;
  gap: 4px;
}

.command-context {
  min-width: 0;
  margin-left: auto;
  overflow: hidden;
  font-family: var(--font-mono-v2);
  text-overflow: ellipsis;
  white-space: nowrap;
}

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

@media (max-width: 767px) {
  .command-dialog {
    width: calc(100vw - 16px);
    margin-top: 8px;
  }

  .command-footer {
    display: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  .command-dialog[open] {
    animation: none;
  }
}
</style>
