<template>
  <v-container
    fluid
    class="pa-0 d-flex flex-column terminal-root terminal-root--classic"
  >
    <v-menu
      v-model="showTermMenu"
      :target="[menuX, menuY]"
      :location="termMenuLocation"
      content-class="terminal-ctx-menu"
    >
      <v-list density="comfortable" nav class="py-1">
        <v-list-item prepend-icon="mdi-content-copy" rounded="lg" @click="termCopy">
          <v-list-item-title>复制</v-list-item-title>
        </v-list-item>
        <v-list-item prepend-icon="mdi-content-paste" rounded="lg" @click="termPaste">
          <v-list-item-title>粘贴</v-list-item-title>
        </v-list-item>
        <v-list-item prepend-icon="mdi-select-all" rounded="lg" @click="termSelectAll">
          <v-list-item-title>全选</v-list-item-title>
        </v-list-item>
        <template v-if="termMenuContext === 'terminal'">
          <v-divider class="my-1" />
          <v-list-item prepend-icon="mdi-delete-sweep" rounded="lg" @click="termClear">
            <v-list-item-title>清屏</v-list-item-title>
          </v-list-item>
          <v-list-item
            prepend-icon="mdi-logout"
            rounded="lg"
            :disabled="!activeSession"
            @click="termDisconnect"
          >
            <v-list-item-title class="text-error">断开连接</v-list-item-title>
          </v-list-item>
        </template>
      </v-list>
    </v-menu>

    <div class="d-flex flex-grow-1 min-h-0 terminal-main-row">
      <div class="d-flex flex-column flex-grow-1 min-w-0 min-h-0">
        <TerminalTabBar
          :sessions="sessions"
          :active-session-id="activeSessionId"
          @switch="switchTab"
          @close="closeTab"
          @new="newSession()"
        />

        <TerminalToolbar
          v-if="sessions.length > 0"
          :session="activeSession"
          :font-size="fontSize"
          :scrollback="scrollback"
          @font-change="changeFontSize"
          @scrollback-change="changeScrollback"
          @fullscreen="toggleFullscreen"
          @disconnect="disconnect"
        />

        <TerminalArea
          ref="areaRef"
          :sessions="sessions"
          :active-session-id="activeSessionId"
          :active-session="activeSession"
          :show-empty="showEmptyPicker"
          @context-menu="onTermContext"
          @pane-ref="setTermRef"
          @reconnect="reconnect"
          @go-servers="router.push('/servers')"
        >
          <template #empty-picker>
            <TerminalServerPicker
              :servers="filteredServers"
              :search="serverSearch"
              :search-history="terminalSearchHistory"
              :loading="serversLoading"
              mode="inline"
              @update:search="onServerSearchUpdate"
              @search-commit="commitServerSearch"
              @select="(id) => newSession(id)"
            />
          </template>
        </TerminalArea>

        <TerminalQuickBar
          :commands="quickCmds"
          :disconnect-disabled="!activeSession"
          @exec="execQuickCmd"
          @disconnect="disconnect"
        />

        <TerminalCmdBar
          ref="cmdBarRef"
          v-model="cmdInput"
          :disabled="cmdBarDisabled"
          @keydown="onCmdKeydown"
          @context-menu="onCmdContext"
        />
      </div>

      <TerminalServerPicker
        mode="sidebar"
        :servers="filteredServers"
        :search="serverSearch"
        :search-history="terminalSearchHistory"
        :loading="serversLoading"
        @update:search="onServerSearchUpdate"
        @search-commit="commitServerSearch"
        @select="(id) => newSession(id)"
      />
    </div>

    <v-dialog v-model="showServerDialog" max-width="400">
      <v-card border>
        <v-card-title>选择服务器</v-card-title>
        <v-card-text>
          <TerminalServerPicker
            :servers="filteredServers"
            :search="serverSearch"
            :search-history="terminalSearchHistory"
            :loading="serversLoading"
            mode="dialog"
            @update:search="onServerSearchUpdate"
            @search-commit="commitServerSearch"
            @select="onDialogSelect"
          />
        </v-card-text>
      </v-card>
    </v-dialog>
  </v-container>
</template>

<script setup lang="ts">
import { ref, computed, onMounted, onBeforeUnmount, watch, inject, type Ref } from 'vue'
import { useRouter } from 'vue-router'
import '@xterm/xterm/css/xterm.css'
import { useSnackbar } from '@/composables/useSnackbar'
import { useTerminalSessions } from '@/composables/terminal/useTerminalSessions'
import TerminalTabBar from '@/components/terminal/TerminalTabBar.vue'
import TerminalToolbar from '@/components/terminal/TerminalToolbar.vue'
import TerminalArea from '@/components/terminal/TerminalArea.vue'
import TerminalCmdBar from '@/components/terminal/TerminalCmdBar.vue'
import TerminalQuickBar from '@/components/terminal/TerminalQuickBar.vue'
import TerminalServerPicker from '@/components/terminal/TerminalServerPicker.vue'

defineOptions({ name: 'TerminalPage' })

const router = useRouter()
const snackbar = useSnackbar()
const nexusDrawer = inject<Ref<boolean>>('nexusDrawer', ref(true))

const {
  sessions,
  activeSessionId,
  activeSession,
  cmdBarDisabled,
  termContainer,
  showServerDialog,
  serverSearch,
  terminalSearchHistory,
  filteredServers,
  showEmptyPicker,
  quickCmds,
  fontSize,
  scrollback,
  changeFontSize,
  changeScrollback,
  cmdInput,
  onCmdKeydown,
  setTermRef,
  switchTab,
  closeTab,
  newSession,
  disconnect,
  reconnect,
  toggleFullscreen,
  loadQuickCmds,
  execQuickCmd,
  loadServers,
  serversLoading,
  commitServerSearch,
  onServerSearchUpdate,
  applyRouteQuery,
  onGlobalKeydown,
  disposeAllSessions,
  getNative,
} = useTerminalSessions(nexusDrawer)

const areaRef = ref<InstanceType<typeof TerminalArea> | null>(null)
const cmdBarRef = ref<InstanceType<typeof TerminalCmdBar> | null>(null)

watch(
  () => areaRef.value?.containerRef,
  (el) => {
    termContainer.value = el ?? null
  },
  { flush: 'post' },
)

const showTermMenu = ref(false)
const menuX = ref(0)
const menuY = ref(0)
const termMenuContext = ref<'terminal' | 'command'>('terminal')
const termMenuLocation = computed(() =>
  menuY.value > window.innerHeight * 0.55 ? 'top end' : 'bottom end',
)

function openTermMenu(e: MouseEvent, context: 'terminal' | 'command') {
  e.preventDefault()
  termMenuContext.value = context
  menuX.value = e.clientX
  menuY.value = e.clientY
  showTermMenu.value = true
}

function onTermContext(e: MouseEvent) {
  openTermMenu(e, 'terminal')
}

function onCmdContext(e: MouseEvent) {
  openTermMenu(e, 'command')
}

function onDialogSelect(serverId: number) {
  showServerDialog.value = false
  void newSession(serverId)
}

function termCopy() {
  showTermMenu.value = false
  if (termMenuContext.value === 'command') {
    const text = cmdBarRef.value?.getSelectionText() || ''
    if (text) {
      navigator.clipboard.writeText(text).catch(() => snackbar('复制失败', 'error'))
      return
    }
  }
  const sel = window.getSelection()?.toString()
  if (sel) {
    navigator.clipboard.writeText(sel).catch(() => snackbar('复制失败', 'error'))
    return
  }
  const s = activeSession.value
  if (s) {
    const buffer = getNative(s.id)?.term?.getSelection()
    if (buffer) navigator.clipboard.writeText(buffer).catch(() => snackbar('复制失败', 'error'))
  }
}

async function termPaste() {
  showTermMenu.value = false
  try {
    const text = await navigator.clipboard.readText()
    if (!text) return
    if (termMenuContext.value === 'command') {
      await cmdBarRef.value?.insertAtSelection(text)
      return
    }
    const s = activeSession.value
    getNative(s?.id || '')?.term?.paste(text)
  } catch {
    snackbar('剪贴板访问被拒绝', 'warning')
  }
}

function termSelectAll() {
  showTermMenu.value = false
  if (termMenuContext.value === 'command') {
    cmdBarRef.value?.selectAllInput()
    return
  }
  getNative(activeSession.value?.id || '')?.term?.selectAll()
}

function termClear() {
  showTermMenu.value = false
  getNative(activeSession.value?.id || '')?.term?.clear()
}

function termDisconnect() {
  showTermMenu.value = false
  const s = activeSession.value
  if (s) void closeTab(s.id)
}

onMounted(async () => {
  document.addEventListener('keydown', onGlobalKeydown)
  await loadServers()
  await loadQuickCmds()
  await applyRouteQuery()
})

onBeforeUnmount(() => {
  document.removeEventListener('keydown', onGlobalKeydown)
  disposeAllSessions()
})
</script>

<style scoped>
.terminal-root {
  flex: 1 1 auto;
  min-height: 0;
  min-width: 0;
  width: 100%;
  max-width: 100%;
  height: 100%;
  box-sizing: border-box;
}
.terminal-root--classic {
  background: #000000;
}
.terminal-main-row {
  min-height: 0;
}
.font-mono {
  font-family: 'Cascadia Code', 'Fira Code', 'JetBrains Mono', Menlo, monospace;
}
:deep(.xterm),
:deep(.xterm-viewport),
:deep(.xterm-screen) {
  background-color: #000000 !important;
}
:deep(.xterm) {
  /* 顶部不加 padding，避免首行字符被 overflow 裁切 */
  padding: 0 4px 4px;
  height: 100%;
  box-sizing: border-box;
}
:deep(.xterm-viewport) {
  overflow-y: auto !important;
}
:deep(.terminal-ctx-menu) {
  min-width: 11.5rem;
}
:deep(.terminal-ctx-menu .v-list-item-title) {
  font-size: 1rem;
  font-weight: 500;
}
:deep(.terminal-ctx-menu .v-icon) {
  font-size: 1.35rem;
}
</style>
