<template>
  <div
    v-if="tabs.length"
    class="global-browser-fixed"
    :class="{ 'global-browser-fixed--maximized': maximized }"
  >
    <v-card border rounded="0" class="global-browser-panel d-flex flex-column h-100">
      <div class="global-browser-toolbar d-flex align-center flex-shrink-0">
        <v-tabs
          :model-value="activeTabId ?? undefined"
          density="compact"
          show-arrows
          class="global-browser-tabs flex-grow-1 min-w-0"
          @update:model-value="onTabSelected"
        >
          <v-tab v-for="tab in tabs" :key="tab.id" :value="tab.id" class="text-none px-2">
            <span class="text-truncate" style="max-width: 120px">{{ tabLabel(tab) }}</span>
            <v-btn
              v-if="tabs.length > 1"
              icon="mdi-close"
              size="x-small"
              variant="text"
              class="ml-1 opacity-60"
              density="compact"
              @click.stop="closeTab(tab.id)"
            />
          </v-tab>
        </v-tabs>

        <v-btn size="small" variant="text" icon="mdi-plus" title="新标签" density="compact" @click="newEmptyTab" />
        <v-divider vertical class="mx-1" style="height: 20px; align-self: center" />
        <v-btn size="small" variant="text" icon="mdi-history" title="浏览记录" density="compact" @click="showHistory = !showHistory" />
        <v-btn size="small" variant="text" icon="mdi-restart" title="重启浏览器（保留历史记录）" density="compact" @click="onRestart" />
        <v-btn
          size="small"
          variant="text"
          :icon="maximized ? 'mdi-fullscreen-exit' : 'mdi-fullscreen'"
          density="compact"
          title="全屏"
          class="mr-1"
          @click="maximized = !maximized"
        />
      </div>

      <div class="global-browser-nav d-flex align-center px-2 py-1 flex-shrink-0 border-b">
        <v-btn icon="mdi-arrow-left" variant="text" size="small" :disabled="!canGoBack" @click="onGoBack" />
        <v-btn icon="mdi-arrow-right" variant="text" size="small" :disabled="!canGoForward" @click="onGoForward" />
        <v-btn icon="mdi-refresh" variant="text" size="small" :disabled="!activeTab?.url" @click="onRefresh" />
        <v-text-field
          v-model="addressDraft"
          density="compact"
          variant="outlined"
          hide-details
          placeholder="https://example.com"
          prepend-inner-icon="mdi-web"
          class="global-browser-url mx-2"
          @keydown.enter.prevent="onGo"
        />
        <v-btn color="primary" variant="flat" size="small" class="text-none" @click="onGo">打开</v-btn>
        <v-btn icon="mdi-open-in-new" variant="text" size="small" :disabled="!activeTab?.url" @click="openExternal" />
      </div>

      <v-alert
        v-if="displayError"
        type="warning"
        density="compact"
        variant="tonal"
        class="ma-2 mb-0 flex-shrink-0"
        closable
        @click:close="clearErrors"
      >
        {{ displayError }}
      </v-alert>

      <div class="global-browser-main d-flex flex-grow-1 min-h-0">
        <aside v-if="showHistory" class="global-browser-history flex-shrink-0 border-e">
          <div class="text-caption font-weight-medium px-3 py-2">浏览记录（已同步账号）</div>
          <v-list density="compact" nav class="py-0 global-browser-history-list">
            <v-list-item
              v-for="(visit, idx) in visits"
              :key="`${visit.at}-${idx}`"
              :title="visit.title"
              :subtitle="visit.url"
              @click="openFromHistory(visit.url)"
            />
            <v-list-item v-if="!visits.length" title="暂无记录" disabled />
          </v-list>
        </aside>

        <div class="global-browser-content flex-grow-1 d-flex flex-column min-w-0 min-h-0">
          <div
            v-if="!activeTab?.url"
            class="flex-grow-1 d-flex flex-column align-center justify-center text-medium-emphasis pa-4"
          >
            <v-icon icon="mdi-web" size="48" class="mb-3 opacity-50" />
            <p class="text-body-2 text-center">输入地址后按回车或点「打开」</p>
            <p class="text-caption mt-2 text-center">
              由 Worker 上的 Chromium 远程渲染，不受 iframe 嵌入限制。
            </p>
          </div>
          <div v-else class="global-browser-canvas-wrap flex-grow-1 d-flex flex-column min-h-0">
            <div v-if="connecting" class="d-flex align-center justify-center flex-grow-1">
              <v-progress-circular indeterminate color="primary" />
              <span class="ml-3 text-body-2">正在连接远程浏览器…</span>
            </div>
            <canvas
              v-show="connected"
              ref="canvasRef"
              class="global-browser-canvas flex-grow-1"
              tabindex="0"
              @mousemove="onCanvasMouseMove"
              @mousedown="onCanvasMouseDown"
              @mouseup="onCanvasMouseUp"
              @wheel.prevent="onCanvasWheel"
              @keydown="onCanvasKeyDown"
              @contextmenu.prevent
            />
          </div>
        </div>
      </div>
    </v-card>
  </div>

  <v-dialog v-model="showRestartConfirm" max-width="400">
    <v-card border>
      <v-card-title>重启浏览器？</v-card-title>
      <v-card-text>将关闭所有标签并打开空白页，浏览历史记录会保留。</v-card-text>
      <v-card-actions>
        <v-spacer />
        <v-btn variant="text" @click="showRestartConfirm = false">取消</v-btn>
        <v-btn color="primary" variant="flat" @click="confirmRestart">重启</v-btn>
      </v-card-actions>
    </v-card>
  </v-dialog>
</template>

<script setup lang="ts">
import { computed, nextTick, onMounted, ref, watch } from 'vue'
import { useGlobalBrowser } from '@/composables/useGlobalBrowser'
import { useRemoteBrowserSession } from '@/composables/useRemoteBrowserSession'

const showHistory = ref(false)
const showRestartConfirm = ref(false)
const maximized = ref(false)
const canvasRef = ref<HTMLCanvasElement | null>(null)

const {
  lastError,
  addressDraft,
  visits,
  tabs,
  activeTabId,
  activeTab,
  canGoBack,
  canGoForward,
  tabLabel,
  openPanel,
  restartBrowser,
  navigate,
  updateActiveFromRemote,
  goBack,
  goForward,
  openExternal,
  switchTab,
  closeTab,
  newEmptyTab,
  openFromHistory,
  bootstrap,
} = useGlobalBrowser()

const {
  connected,
  connecting,
  remoteError,
  setCanvas,
  setPageInfoHandler,
  connect,
  disconnect,
  navigate: remoteNavigate,
  reload,
  goBack: remoteGoBack,
  goForward: remoteGoForward,
  onCanvasMouseMove,
  onCanvasMouseDown,
  onCanvasMouseUp,
  onCanvasWheel,
  onCanvasKeyDown,
} = useRemoteBrowserSession()

const displayError = computed(() => remoteError.value || lastError.value)

function clearErrors() {
  lastError.value = null
  if (remoteError.value) remoteError.value = null
}

setPageInfoHandler((url, title) => updateActiveFromRemote(url, title))

async function ensureRemoteSession() {
  if (!activeTab.value?.url || connecting.value || connected.value) return
  await nextTick()
  if (canvasRef.value) setCanvas(canvasRef.value)
  const w = Math.max(640, Math.floor(canvasRef.value?.clientWidth || 1280))
  const h = Math.max(480, Math.floor(canvasRef.value?.clientHeight || 360))
  await connect(w, h)
  if (connected.value && activeTab.value?.url) {
    remoteNavigate(activeTab.value.url)
  }
}

watch(activeTab, () => {
  if (activeTab.value?.url) {
    openPanel()
    void ensureRemoteSession()
  }
}, { flush: 'post' })

watch(activeTabId, () => {
  disconnect()
  if (activeTab.value?.url) {
    void ensureRemoteSession()
  }
})

onMounted(async () => {
  await bootstrap()
  if (!tabs.value.length) {
    newEmptyTab()
  }
  openPanel()
  if (activeTab.value?.url) {
    void ensureRemoteSession()
  }
})

function onTabSelected(id: unknown) {
  if (typeof id === 'string') switchTab(id)
}

function onGo() {
  if (navigate(addressDraft.value)) {
    void ensureRemoteSession().then(() => {
      if (activeTab.value?.url) remoteNavigate(activeTab.value.url)
    })
  }
}

function onRestart() {
  showRestartConfirm.value = true
}

function confirmRestart() {
  showRestartConfirm.value = false
  disconnect()
  restartBrowser()
}

function onRefresh() {
  if (connected.value) reload()
}

function onGoBack() {
  goBack()
  if (connected.value) remoteGoBack()
}

function onGoForward() {
  goForward()
  if (connected.value) remoteGoForward()
}
</script>

<style scoped>
.global-browser-fixed {
  position: fixed;
  top: var(--v-layout-top, 64px);
  left: var(--v-layout-left, 0);
  right: 0;
  z-index: 1004;
  height: var(--nexus-browser-dock-height, 420px);
  display: flex;
  flex-direction: column;
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.12);
}
.global-browser-fixed--maximized {
  height: calc(100dvh - var(--v-layout-top, 64px)) !important;
}
.global-browser-panel {
  overflow: hidden;
  height: 100%;
  background: rgb(var(--v-theme-surface));
  border-radius: 0 !important;
}
.global-browser-toolbar {
  height: 40px;
  min-height: 40px;
  border-bottom: 1px solid rgba(var(--v-border-color), var(--v-border-opacity));
}
.global-browser-nav {
  background: rgb(var(--v-theme-surface));
}
.global-browser-url {
  flex: 1 1 auto;
  min-width: 100px;
}
.global-browser-main {
  min-height: 0;
}
.global-browser-history {
  width: 280px;
  max-width: 40%;
  background: rgb(var(--v-theme-surface));
}
.global-browser-history-list {
  max-height: 100%;
  overflow-y: auto;
}
.global-browser-canvas-wrap {
  min-height: 0;
  background: #1a1a1a;
}
.global-browser-canvas {
  width: 100%;
  min-height: 0;
  cursor: default;
  outline: none;
}
</style>
