<template>
  <div class="workspace-3d-wrap" :class="{ 'workspace-3d--canvas-only': canvasOnly || hideToolbar }">
    <div v-if="!(canvasOnly || hideToolbar)" class="workspace-3d-toolbar">
      <el-tag :type="readOnly ? 'info' : 'success'" effect="dark" size="small">
        {{ readOnly ? '只读' : '可交互' }}
      </el-tag>
      <span class="hint">webVRender · http://{{ resolvedHost }} · scope={{ scope }}</span>
      <div class="spacer" />
      <el-tag v-if="lastPick" type="warning" size="small">
        Pick ({{ lastPick.x.toFixed(0) }}, {{ lastPick.y.toFixed(0) }})
      </el-tag>
      <el-tag v-if="lastSelect.length" type="primary" size="small">
        Selected: {{ lastSelect.length }}
      </el-tag>
      <el-button size="small" :icon="Refresh" @click="reload">重载</el-button>
      <el-button size="small" :icon="FullScreen" @click="enterFullscreen">全屏</el-button>
    </div>
    <div ref="frameWrap" class="workspace-3d-frame">
      <iframe
        v-if="iframeSrc"
        ref="frame"
        :src="iframeSrc"
        class="workspace-3d-iframe"
        allow="fullscreen"
        @load="onReady" />
      <div v-if="!loaded" class="workspace-3d-mask">
        <el-icon class="is-loading" size="32"><Loading /></el-icon>
        <span>正在连接 webVRender (http://{{ resolvedHost }}) ...</span>
        <span class="muted">如长时间未加载，请确认 SimpleLite 已以 Web-Enabled 模式启动且 8223 端口可达。</span>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { computed, onBeforeUnmount, onMounted, ref } from 'vue'
import { Refresh, FullScreen, Loading } from '@element-plus/icons-vue'
import type { Scope } from '@/types/auth'

interface PickEvent { x: number; y: number }

const props = withDefaults(defineProps<{
  host?: string
  scope?: Scope
  token?: string
  readOnly?: boolean
  /** 嵌入平台页时传 true：SimpleLite 仅显示底栏（对齐/选择/右击/图层/内容/录制回放） */
  embedUi?: boolean
  /**
   * 地图编辑器纯画布模式：比 embedUi 更裸，连底栏都不创建。
   * 设为 true 时 Vue 端会先调 /declareCanvasOnly，并在 iframe URL 上加 ?ui=canvas-only。
   * 适用于 MapEditorView，所有 UI（顶栏 / 工具栏 / 属性面板）由 Vue 接管。
   */
  canvasOnly?: boolean
  /** 隐藏 Vue 端的顶部信息工具条（迷榖 / 重载 / 全屏）。地图编辑器内推荐设为 true，由 EditTopBar 接管。 */
  hideToolbar?: boolean
}>(), {
  host: undefined,
  scope: 'Platform',
  token: '',
  readOnly: false,
  embedUi: false,
  canvasOnly: false,
  hideToolbar: false
})

const emit = defineEmits<{
  (e: 'pick', wp: PickEvent): void
  (e: 'select', names: string[]): void
  (e: 'ready'): void
}>()

const frame = ref<HTMLIFrameElement>()
const frameWrap = ref<HTMLDivElement>()
const loaded = ref(false)
const lastPick = ref<PickEvent | null>(null)
const lastSelect = ref<string[]>([])
const iframeSrc = ref<string>('')

const resolvedHost = computed(() => props.host ?? (import.meta.env.VITE_VRENDER_HOST as string | undefined) ?? 'localhost:8223')

const vrUrl = computed(() => {
  const qs = new URLSearchParams()
  qs.set('scope', props.scope ?? 'Platform')
  if (props.token) qs.set('token', props.token)
  qs.set('ro', props.readOnly ? '1' : '0')
  if (props.canvasOnly) qs.set('ui', 'canvas-only')
  else if (props.embedUi) qs.set('ui', 'embed')
  return `http://${resolvedHost.value}/?${qs.toString()}`
})

/**
 * 嵌入 / canvas-only 模式必须在 webVRender 主页加载（即发起 WebSocket 连接）之前先打一次
 * 对应的 GET 声明端点，让 SimpleLite 把"下一个连入的 WebTerminal"打上对应模式标签。
 * 否则 SimpleLite 拿不到任何提示（CycleGUI 不会把 URL query 透传给 Terminal），
 * 会默认创建完整工作区面板（工作台 / 浮动条 / CAD / 底栏），违反平台 UI 接管的要求。
 */
async function declareEmbedIfNeeded() {
  const endpoint = props.canvasOnly
    ? '/declareCanvasOnly'
    : props.embedUi
      ? '/declareEmbedUi'
      : null
  if (!endpoint) return
  try {
    await fetch(`http://${resolvedHost.value}${endpoint}`, {
      method: 'GET',
      mode: 'no-cors',
      cache: 'no-store',
      credentials: 'omit',
      keepalive: true
    })
  } catch (err) {
    console.warn(`[Workspace3D] ${endpoint} 请求失败，SimpleLite 可能仍以完整面板模式启动：`, err)
  }
}

async function prepareAndLoad() {
  loaded.value = false
  await declareEmbedIfNeeded()
  iframeSrc.value = vrUrl.value
}

function onReady() {
  loaded.value = true
  emit('ready')
}

function onMessage(ev: MessageEvent) {
  if (!frame.value || ev.source !== frame.value.contentWindow) return
  const msg = ev.data
  if (!msg || typeof msg !== 'object') return
  if (msg.type === 'workspace.pick' && msg.payload && typeof msg.payload.x === 'number') {
    lastPick.value = msg.payload
    emit('pick', msg.payload)
  } else if (msg.type === 'workspace.select' && Array.isArray(msg.payload)) {
    lastSelect.value = msg.payload as string[]
    emit('select', msg.payload as string[])
  }
}

function reload() {
  prepareAndLoad()
}

function enterFullscreen() {
  const el = frameWrap.value
  if (!el) return
  if (document.fullscreenElement) document.exitFullscreen()
  else el.requestFullscreen()
}

onMounted(() => {
  window.addEventListener('message', onMessage)
  prepareAndLoad()
})

onBeforeUnmount(() => {
  window.removeEventListener('message', onMessage)
})

defineExpose({ reload, enterFullscreen })
</script>

<style scoped>
.workspace-3d-wrap {
  display: flex; flex-direction: column; height: 100%; min-height: 480px;
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: var(--mg-radius, 16px);
  background: rgba(15, 4, 32, 0.45);
  backdrop-filter: blur(18px) saturate(140%);
  -webkit-backdrop-filter: blur(18px) saturate(140%);
  box-shadow: 0 8px 24px rgba(10, 2, 16, 0.35), 0 0 0 1px rgba(255, 255, 255, 0.06) inset;
  overflow: hidden;
  transition: all .25s cubic-bezier(.25, .8, .25, 1);
}
.workspace-3d-wrap.workspace-3d--canvas-only {
  border: 0;
  border-radius: 0;
  min-height: 0;
  background: transparent;
  box-shadow: none;
}
.workspace-3d-toolbar {
  display: flex; align-items: center; gap: 8px;
  padding: 8px 14px;
  background: rgba(255, 255, 255, 0.04);
  border-bottom: 1px solid rgba(255, 255, 255, 0.08);
  font-size: 12px;
  color: rgba(232, 215, 245, 0.85);
}
.workspace-3d-toolbar .hint {
  color: rgba(201, 166, 227, 0.7);
  font-family: ui-monospace, Menlo, Consolas, monospace;
  font-size: 11.5px;
}
.workspace-3d-toolbar .spacer { flex: 1; }
.workspace-3d-frame {
  flex: 1; position: relative;
  background: radial-gradient(ellipse at 50% 40%, #2d1456 0%, #1a0930 50%, #0f0420 100%);
}
.workspace-3d-iframe {
  width: 100%; height: 100%; border: 0; background: transparent; display: block;
}
.workspace-3d-mask {
  position: absolute; inset: 0; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 10px;
  background:
    radial-gradient(ellipse at center, rgba(var(--mg-primary-rgb), 0.35) 0%, rgba(var(--mg-bg-app-deep-rgb), 0.92) 80%),
    rgba(var(--mg-bg-app-deep-rgb), 0.85);
  color: rgba(232, 220, 255, 0.92);
  font-size: 13px;
  backdrop-filter: blur(10px);
}
.workspace-3d-mask .muted { color: rgba(var(--mg-accent-rgb), 0.7); font-size: 12px; }
.workspace-3d-mask .el-icon { color: var(--mg-accent); filter: drop-shadow(0 0 10px rgba(var(--mg-accent-rgb), 0.6)); }
</style>
