<script setup lang="ts">
import { computed, onMounted, onUnmounted, ref, watch } from 'vue'
import { RouterView, useRoute, useRouter } from 'vue-router'
import { useAuthStore } from './stores/auth'
import AppSidebar from './components/layout/AppSidebar.vue'
import AppHeader from './components/layout/AppHeader.vue'
import ToastContainer from './components/ui/ToastContainer.vue'
import GalaxyBackground from './components/background/GalaxyBackground.vue'
import OpenClawConnectionNotice from './components/openclaw/OpenClawConnectionNotice.vue'
import { useOpenClawStore } from './stores/openclaw'
import { useChatStore } from './stores/chat'
import { useMissionControlUiStore } from './stores/missionControlUi'
import CommandPalette from './components/mission-control/CommandPalette.vue'
import IrisChat from './components/dashboard/v2/IrisChat.vue'
import { buildMissionControlContext } from './utils/missionControlContext'
import { useTaskBoard } from './api/taskBoard'
import { useOpenClawOverviewQuery } from './api/openclawRuntime'
import { subscribeDomainEventState, type SseConnectionState } from './services/domainEvents'
import OperationResultTray from './components/mission-control/OperationResultTray.vue'

const auth = useAuthStore()
const openClaw = useOpenClawStore()
const chat = useChatStore()
const missionControlUi = useMissionControlUiStore()
const route = useRoute()
const router = useRouter()
const taskBoard = useTaskBoard(
  50,
  computed(() => auth.isAuthenticated && route.name !== 'Login'),
)
const overviewQuery = useOpenClawOverviewQuery(
  computed(() => auth.isAuthenticated && route.name !== 'Login'),
)
let unsubscribeDomainState: (() => void) | null = null

const activeView = computed(() => {
  if (route.name === 'Settings') return 'Settings'
  if (route.name === 'AgentDetail' || route.name === 'AgentCreate' || route.name === 'AgentProposalDetail') return 'Agents'
  if (route.name === 'ProjectDetail') return 'Projects'
  if (route.name === 'TaskDetail') return 'Task Board'
  if (route.name === 'RunDetail') return 'Run Control'
  return String(route.name ?? 'Dashboard')
})

const navigate = () => {
  mobileNavOpen.value = false
}
const mobileNavOpen = ref(false)

const queuedTasks = computed(() =>
  taskBoard.board.value.offen.length
  + taskBoard.board.value.inProgress.length
  + taskBoard.board.value.review.length
  + taskBoard.board.value.blocked.length,
)
const blockedTasks = computed(() => taskBoard.board.value.blocked.length)
const missionContext = computed(() => buildMissionControlContext(route))

function syncAuthenticatedSession(authenticated: boolean) {
  if (authenticated) return
  chat.stopPolling()
  missionControlUi.closeCommand()
  missionControlUi.closeIris()
  missionControlUi.dismissOperation()
}

function syncDomainMode(state: SseConnectionState) {
  if (!auth.isAuthenticated || state === 'closed') openClaw.setSyncMode('stopped')
  else if (state === 'open') openClaw.setSyncMode('live')
  else if (state === 'unsupported') openClaw.setSyncMode('polling')
  else openClaw.setSyncMode('connecting')
}

function onGlobalKeydown(event: KeyboardEvent) {
  if ((event.ctrlKey || event.metaKey) && event.key.toLocaleLowerCase() === 'k') {
    event.preventDefault()
    if (!auth.isAuthenticated) return
    if (missionControlUi.commandOpen) missionControlUi.closeCommand()
    else missionControlUi.openCommand()
  }
}

function askIrisFromCommand() {
  if (!auth.isOwner) return
  missionControlUi.openIris()
}

async function closeIris() {
  missionControlUi.closeIris()
  if (route.query.iris === '1') {
    const query = { ...route.query }
    delete query.iris
    await router.replace({ query })
  }
}

function sendIrisMessage(text: string) {
  if (!auth.isOwner) return
  void chat.sendMessage(text, missionContext.value)
}

watch(
  () => auth.isAuthenticated,
  authenticated => syncAuthenticatedSession(authenticated),
)

watch(
  [
    () => route.query.iris,
    () => auth.isAuthenticated,
    () => auth.isOwner,
  ],
  ([value, isAuthenticated, isOwner]) => {
    if (!isOwner) {
      missionControlUi.closeIris()
      chat.stopPolling()
      if (value === '1' && isAuthenticated) void closeIris()
      return
    }
    if (value === '1' && isAuthenticated) missionControlUi.openIris()
  },
  { immediate: true },
)

watch(
  () => missionControlUi.irisOpen,
  isOpen => {
    if (isOpen && auth.isAuthenticated && auth.isOwner) chat.startPolling()
    else chat.stopPolling()
  },
)

onMounted(() => {
  syncAuthenticatedSession(auth.isAuthenticated)
  unsubscribeDomainState = subscribeDomainEventState(syncDomainMode)
  document.addEventListener('keydown', onGlobalKeydown)
})

onUnmounted(() => {
  unsubscribeDomainState?.()
  unsubscribeDomainState = null
  openClaw.setSyncMode('stopped')
  chat.stopPolling()
  document.removeEventListener('keydown', onGlobalKeydown)
})
</script>

<template>
  <RouterView v-if="route.name === 'Login' || route.name === 'Dashboard'" />
  <div v-else class="shell legacy-shell">
    <GalaxyBackground aria-hidden="true" />
    <AppSidebar
      :active-view="activeView"
      :mobile-nav-open="mobileNavOpen"
      :queued-tasks="queuedTasks"
      :incidents="blockedTasks"
      @navigate="navigate"
    />
    <button
      v-if="mobileNavOpen"
      type="button"
      class="mobile-nav-backdrop"
      aria-label="Close navigation"
      @click="mobileNavOpen = false"
    ></button>

    <main class="legacy-main">
      <AppHeader
        :connected="overviewQuery.data.value?.connection.connected ?? false"
        :command-open="missionControlUi.commandOpen"
        :iris-open="missionControlUi.irisOpen"
        :can-open-iris="auth.isOwner"
        @toggle-mobile-nav="mobileNavOpen = !mobileNavOpen"
        @open-command="missionControlUi.openCommand"
        @open-iris="missionControlUi.openIris"
      />

      <section
        class="content legacy-content v2-scroll"
        :data-route="String(route.name ?? '')"
      >
        <OpenClawConnectionNotice />
        <RouterView />
      </section>
    </main>
    <ToastContainer />
  </div>

  <CommandPalette
    v-if="auth.isAuthenticated"
    :open="missionControlUi.commandOpen"
    :context="missionContext"
    :can-open-iris="auth.isOwner"
    :can-start-run="auth.isOwner"
    @close="missionControlUi.closeCommand"
    @ask-iris="askIrisFromCommand"
  />
  <IrisChat
    v-if="auth.isAuthenticated && auth.isOwner && missionControlUi.irisOpen"
    :messages="chat.messageList"
    :is-thinking="chat.isThinking"
    :error="chat.error"
    :context="missionContext"
    @send="sendIrisMessage"
    @close="closeIris"
  />
  <OperationResultTray
    v-if="auth.isAuthenticated && missionControlUi.operationResult"
    :result="missionControlUi.operationResult"
    :title="missionControlUi.operationTitle"
    @close="missionControlUi.dismissOperation"
  />
</template>

<style scoped>
.shell {
  display: flex;
  height: 100dvh;
  overflow: hidden;
  position: relative;
  background: var(--space-0);
}

.legacy-main {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
  position: relative;
  z-index: 1;
}

.content {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 12px;
  overflow-y: auto;
  overflow-x: hidden;
  padding: var(--page-pad);
}

.content > :last-child {
  flex: 1 0 auto;
}

.page-heading {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  margin-bottom: 20px;
  gap: 12px;
}
.page-heading h1 { margin: 0; }
.page-heading p { margin: 4px 0 0; color: var(--tx-2); }
.eyebrow {
  display: inline-block;
  margin-bottom: 4px;
  font-family: var(--font-mono-v2);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .12em;
  color: var(--a-mid);
  text-transform: uppercase;
}
.refresh {
  flex-shrink: 0;
}

.spin { animation: spin 1s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }

.mobile-nav-backdrop {
  display: none;
}

@media (max-width: 900px) {
  .content {
    padding: var(--page-pad-mobile);
  }

  .mobile-nav-backdrop {
    display: block;
    position: fixed;
    inset: 0;
    z-index: 50;
    border: 0;
    background: color-mix(in srgb, var(--space-0) 62%, transparent);
    backdrop-filter: blur(4px);
  }
}
</style>
