<template>
  <n-drawer v-model:show="visible" :width="drawerWidth" placement="right">
    <n-drawer-content :title="title" closable>
      <div class="plm-model-drawer">
        <n-descriptions v-if="metaLines.length" :column="2" size="small" label-placement="left" bordered>
          <n-descriptions-item v-for="item in metaLines" :key="item.label" :label="item.label">
            {{ item.value }}
          </n-descriptions-item>
        </n-descriptions>

        <div v-if="converting" class="plm-model-drawer__status">
          <n-spin size="large" />
          <p>正在从 PLM 获取并转换模型，请稍候…</p>
          <n-text depth="3">首次查看可能需要 30 秒～数分钟</n-text>
        </div>

        <CadModelViewer v-else-if="previewUrl" 
        :modelUrl="previewUrl"
        :glbDownloadUrl ="glbDownloadUrl"
        :stpDownloadUrl = "stpDownloadUrl"
        class="plm-model-drawer__viewer" />

        <n-result
          v-else-if="error"
          status="warning"
          :title="error"
          description="请确认 PLM 中已维护该物料的三维模型"
        />

        <n-empty v-else-if="!loading" description="暂无模型数据" />
      </div>
    </n-drawer-content>
  </n-drawer>
</template>

<script setup lang="ts">
import { ref, computed } from 'vue'
import {
  NDrawer, NDrawerContent, NDescriptions, NDescriptionsItem,
  NSpin, NText, NEmpty, NResult,
} from 'naive-ui'
import CadModelViewer from '@/components/CadModelViewer.vue'
import { plmModelApi, type PlmModelPreviewQuery, type PlmModelPreviewResult, type PlmModelOpenContext } from '@/api/plmModel'

export type { PlmModelOpenContext }

const visible = ref(false)
const loading = ref(false)
const converting = ref(false)
const previewUrl = ref('')
const glbDownloadUrl = ref('')
const stpDownloadUrl = ref('')
const error = ref('')
const context = ref<PlmModelOpenContext>({})
const resultMeta = ref<PlmModelPreviewResult | null>(null)

const drawerWidth = computed(() => Math.min(window.innerWidth * 0.88, 960))
const title = computed(() => context.value.title || '三维模型')
const metaLines = computed(() => {
  const lines: { label: string; value: string }[] = []
  const name = resultMeta.value?.materialName || context.value.materialName
  const code = resultMeta.value?.materialCode || context.value.materialCode
  const drawing = resultMeta.value?.drawingNo || context.value.drawingNo
  if (name) lines.push({ label: '物料名称', value: name })
  if (code) lines.push({ label: '物料编码', value: code })
  if (drawing) lines.push({ label: '图号', value: drawing })
  if (resultMeta.value?.originalFormat) {
    lines.push({ label: '源格式', value: resultMeta.value.originalFormat.toUpperCase() })
  }
  return lines
})

function sleep(ms: number) {
  return new Promise(resolve => setTimeout(resolve, ms))
}

async function fetchPreview(query: PlmModelPreviewQuery): Promise<PlmModelPreviewResult> {
  const maxAttempts = 90
  for (let i = 0; i < maxAttempts; i++) {    
    const res = await plmModelApi.getPreview(query)

    if (res.status === 'ready' || res.status === 'failed' || res.status === 'not_found') {
      return res
    }
    converting.value = true
    await sleep(2000)
  }
  return { status: 'failed', message: '模型转换超时，请稍后重试' }
}

async function open(ctx: PlmModelOpenContext) {
  context.value = ctx
  resultMeta.value = null
  previewUrl.value = ''
  error.value = ''
  converting.value = true
  loading.value = true
  visible.value = true

  try {
    const res = await fetchPreview({
      orderItemId: ctx.orderItemId,
      materialCode: ctx.materialCode,
      drawingNo: ctx.drawingNo || ctx.materialCode,
      processPlanId: ctx.processPlanId,
      dispatchId: ctx.dispatchId,
    })
    
    resultMeta.value = res
    
    
    if (res.status === 'ready' && res.previewUrl) {
      previewUrl.value = res.previewUrl
      glbDownloadUrl.value = res.glbDownloadUrl
      stpDownloadUrl.value = res.stpDownloadUrl
    } else {
      error.value = res.message || (res.status === 'not_found' ? '未找到该物料的三维模型' : '模型预览失败')
    }
  } catch (e) {
    error.value = e instanceof Error ? e.message : '获取模型预览失败'
  } finally {
    loading.value = false
    converting.value = false
  }
}

defineExpose({ open })
</script>

<style scoped>
.plm-model-drawer {
  display: flex;
  flex-direction: column;
  gap: 12px;
  height: calc(100vh - 120px);
}

.plm-model-drawer__status {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: 360px;
}

.plm-model-drawer__viewer {
  flex: 1;
  min-height: 420px;
}
</style>
