<template>
  <div class="yak-industry-chain">
    <map-scene
      ref="mapSceneRef"
      class="industry-map-scene"
      :active-layer="industryMapLayer"
      :map-ranking="mapRanking"
      @feature-info="handleMapFeatureInfo"
    />
    <div class="industry-map-scrim"></div>
    <div v-if="!mapReady" class="industry-map-loading">3D地图加载中</div>

    <div v-if="leftStagePanels.length" class="fgw-left industry-side-panel industry-side-panel--left">
      <div class="fgw-side-stack industry-side-stack is-left">
        <m-card
          v-for="panel in leftStagePanels"
          :key="panel.key"
          class="fgw-side-card industry-side-card left-card"
          :title="panel.title"
          :width="sideCardWidth"
          :height="panel.height"
        >
          <business-panel-renderer
            v-if="panel.renderer === 'business'"
            :panel="panel"
            compact
            @row-select="handleIndustryListSelect"
          />
          <div v-else-if="panel.renderer === 'ledger'" class="industry-ledger-list">
            <div v-for="item in panel.rows" :key="item.key" class="industry-ledger-row">
              <div>
                <strong>{{ item.name }}</strong>
                <span>{{ item.typeName }} / {{ item.town }}</span>
              </div>
              <em>{{ item.valueText }}</em>
            </div>
          </div>
        </m-card>
      </div>
    </div>

    <div v-if="rightStagePanels.length" class="fgw-right industry-side-panel industry-side-panel--right">
      <div class="fgw-side-stack industry-side-stack is-right">
        <m-card
          v-for="panel in rightStagePanels"
          :key="panel.key"
          class="fgw-side-card industry-side-card right-card"
          :title="panel.title"
          :width="sideCardWidth"
          :height="panel.height"
        >
          <business-panel-renderer
            v-if="panel.renderer === 'business'"
            :panel="panel"
            compact
            @row-select="handleIndustryListSelect"
          />
          <div v-else-if="panel.renderer === 'ledger'" class="industry-ledger-list">
            <div v-for="item in panel.rows" :key="item.key" class="industry-ledger-row">
              <div>
                <strong>{{ item.name }}</strong>
                <span>{{ item.typeName }} / {{ item.town }}</span>
              </div>
              <em>{{ item.valueText }}</em>
            </div>
          </div>
        </m-card>
      </div>
    </div>

    <div v-if="selectedPoint" class="industry-point-detail" :style="pointDetailStyle">
      <div class="industry-point-detail__head">
        <span>{{ selectedPointTitle }}</span>
        <button type="button" title="关闭" @click="clearSelectedPoint">×</button>
      </div>
      <div class="industry-point-detail__name">{{ selectedPointName }}</div>
      <div class="industry-point-detail__grid">
        <div v-for="row in selectedPointRows" :key="row.label" class="industry-point-detail__row">
          <span>{{ row.label }}</span>
          <strong>{{ row.value }}</strong>
        </div>
      </div>
    </div>

    <div class="industry-bottom-switcher">
      <topic-switcher
        :model-value="activeStageKey"
        :topics="stageSwitcherTopics"
        @update:model-value="handleStageSelect"
      />
    </div>
  </div>
</template>

<script setup>
import { computed, nextTick, onBeforeUnmount, onMounted, ref, watch } from "vue"
import mCard from "@/components/mCard/index.vue"
import MapScene from "@/views/forestGrassWet/map.vue"
import BusinessPanelRenderer from "@/views/forestGrassWet/components/BusinessPanelRenderer.vue"
import TopicSwitcher from "@/views/forestGrassWet/components/TopicSwitcher.vue"
import { Assets } from "@/views/forestGrassWet/assets"
import { getLayerByKey } from "@/config/layers"
import {
  getStageDef,
  getStagePanelConfig,
  getPointExtraRows,
  industryStageDefs,
  getStageTopStats,
} from "./data"

const props = defineProps({
  active: {
    type: Boolean,
    default: true,
  },
})
const emit = defineEmits(["module-stats", "loading-progress", "map-ready"])
const sideCardWidth = 398
const activeStageKey = ref("family-pasture")
const mapSceneRef = ref(null)
const mapReady = ref(false)
const selectedPoint = ref(null)
const selectedPointScreen = ref({ x: 0, y: 0 })
let mapAssets = null
let mapAssetsReady = false
let mapLoadStarted = false
let mapLoadTimer = null
let destroyed = false

const activeStage = computed(() => getStageDef(activeStageKey.value))
const activePanelConfig = computed(() => getStagePanelConfig(activeStageKey.value))
const stagePanelGroups = computed(() => normalizeStagePanelGroups(activePanelConfig.value))
const leftStagePanels = computed(() => stagePanelGroups.value.left)
const rightStagePanels = computed(() => stagePanelGroups.value.right)
const industryMapLayer = computed(() => {
  const layer = getLayerByKey("yak-industry-chain", "yak-industry-points")
  const legend = layer?.legends?.find((item) => item.match?.value === activeStageKey.value)
  if (!layer) return layer
  return {
    ...layer,
    activeLegend: legend || {
      key: `yak-industry-empty-${activeStageKey.value}`,
      name: activeStage.value.name,
      fillColor: activeStage.value.color,
      strokeColor: activeStage.value.color,
      match: { field: "stageKey", value: activeStageKey.value },
    },
  }
})
const stageSwitcherTopics = computed(() =>
  industryStageDefs.map((stage) => ({
    key: stage.key,
    name: stage.name,
    color: stage.color,
    width: stage.width,
  }))
)
const mapRanking = computed(() => ({
  showTownNames: true,
  showBars: false,
  showPointMarkers: true,
  title: `${activeStage.value.name}排行`,
  metricLabel: activeStage.value.metricLabel,
  unit: activeStage.value.unit,
  rows: [],
}))

const selectedPointRows = computed(() => {
  const point = selectedPoint.value
  if (!point) return []
  return [
    { label: "所属环节", value: formatDisplayText(point.stageName) },
    { label: "主体类型", value: formatDisplayText(point.categoryName) },
    { label: "所在乡镇", value: formatDisplayText(point.town) },
    { label: "能力规模", value: formatCapacity(point) },
    { label: "运行状态", value: formatDisplayText(point.status) },
    ...getPointExtraRows(point),
  ].filter((row) => row.value !== undefined && row.value !== null && String(row.value).trim() !== "")
})
const selectedPointTitle = computed(() => formatDisplayText(selectedPoint.value?.categoryName || selectedPoint.value?.stageName))
const selectedPointName = computed(() => formatDisplayText(selectedPoint.value?.name))
const pointDetailStyle = computed(() => {
  const panelWidth = 430
  const panelHeight = 252
  const margin = 24
  const pointerGap = 28
  const point = {
    x: Math.max(margin, Math.min(1920 - margin, Number(selectedPointScreen.value.x || 0))),
    y: Math.max(margin, Math.min(1080 - margin, Number(selectedPointScreen.value.y || 0))),
  }
  const placeLeft = point.x > 1320
  const x = placeLeft
    ? Math.max(margin, point.x - panelWidth - pointerGap)
    : Math.min(1920 - panelWidth - margin, point.x + pointerGap)
  const y = Math.min(Math.max(point.y - panelHeight / 2, 128), 1080 - panelHeight - 116)
  const arrowTop = Math.min(Math.max(point.y - y, 42), panelHeight - 38)
  return {
    left: `${x}px`,
    top: `${y}px`,
    "--point-arrow-top": `${arrowTop}px`,
    "--point-arrow-side": placeLeft ? "100%" : "0px",
    "--point-arrow-offset": placeLeft ? "-1px" : "-9px",
    "--point-arrow-rotate": placeLeft ? "-45deg" : "135deg",
  }
})
onMounted(() => {
  emitIndustryTopStats()
  initIndustryMap()
})

onBeforeUnmount(() => {
  destroyed = true
  if (mapLoadTimer) window.clearTimeout(mapLoadTimer)
  mapSceneRef.value?.destroyMap?.()
})

watch(
  () => props.active,
  (active) => {
    if (!mapSceneRef.value) return
    if (active) {
      scheduleIndustryMapLoad()
      mapSceneRef.value.resume?.()
    } else {
      mapSceneRef.value.pause?.()
    }
  },
)

function handleStageSelect(key) {
  if (key === activeStageKey.value) return
  activeStageKey.value = key
  clearSelectedPoint()
  emitIndustryTopStats(key)
}

function normalizeStagePanelGroups(config = {}) {
  const left = filterDisplayPanels(config.left)
  const right = filterDisplayPanels(config.right)
  if (right.length) {
    return { left, right }
  }
  const panels = [...left, ...right]
  if (panels.length <= 4) {
    return { left: panels, right: [] }
  }
  return { left, right }
}

function filterDisplayPanels(panels = []) {
  return panels.filter((panel) => panel?.type !== "iconMetric")
}

function emitIndustryTopStats(stageKey = activeStageKey.value) {
  emit("module-stats", {
    moduleKey: "yak-industry-chain",
    items: getStageTopStats(stageKey),
  })
}

function initIndustryMap() {
  mapAssets = new Assets()
  mapAssetsReady = false
  emit("loading-progress", { progress: 0 })
  mapAssets.instance?.on?.("onProgress", (path, itemsLoaded, itemsTotal) => {
    const total = itemsTotal || 1
    emit("loading-progress", {
      progress: Math.floor((itemsLoaded / total) * 100),
      path,
      itemsLoaded,
      itemsTotal,
    })
  })
  mapAssets.ready?.then(() => {
    mapAssetsReady = true
    scheduleIndustryMapLoad()
  }).catch(() => {
    mapReady.value = true
    emit("map-ready")
  })
}

function scheduleIndustryMapLoad() {
  if (destroyed || !props.active || !mapAssetsReady || mapLoadStarted) return
  mapLoadStarted = true
  if (mapLoadTimer) window.clearTimeout(mapLoadTimer)
  mapLoadTimer = window.setTimeout(() => {
    mapLoadTimer = null
    loadIndustryMapOnce()
  }, 600)
}

async function loadIndustryMapOnce(attempt = 0) {
  if (destroyed) return
  if (!props.active) {
    mapLoadStarted = false
    return
  }
  await nextTick()
  if (!props.active) {
    mapLoadStarted = false
    return
  }
  const scene = mapSceneRef.value
  scene?.loadMap?.(mapAssets)
  if (scene?.canvasMap) {
    mapReady.value = true
    emit("loading-progress", { progress: 100 })
    emit("map-ready")
    scene.play?.()
    return
  }
  if (attempt < 24) {
    window.setTimeout(() => loadIndustryMapOnce(attempt + 1), 120)
    return
  }
  mapLoadStarted = false
  mapReady.value = true
  emit("map-ready")
}

function handleMapFeatureInfo(payload = {}) {
  const properties = payload.feature?.properties || {}
  if (properties.stageKey) {
    selectedPoint.value = properties
    selectedPointScreen.value = normalizeFeatureScreen(payload.screen)
    return
  }
  selectedPoint.value = null
}

async function handleIndustryListSelect(row = {}) {
  if (!row.canLocate) return
  const stageChanged = Boolean(row.stageKey && row.stageKey !== activeStageKey.value)
  if (stageChanged) {
    activeStageKey.value = row.stageKey
    emitIndustryTopStats(row.stageKey)
    await nextTick()
  }
  const point = buildListPoint(row)
  selectedPoint.value = point
  selectedPointScreen.value = { x: 960, y: 500 }
  window.setTimeout(() => {
    const focusResult = mapSceneRef.value?.focusYakIndustryPoint?.(point)
    syncSelectedPointScreen(point, focusResult)
    window.setTimeout(() => syncSelectedPointScreen(point), 760)
  }, stageChanged ? 320 : 80)
}

function clearSelectedPoint() {
  selectedPoint.value = null
  const canvasMap = mapSceneRef.value?.canvasMap?.value || mapSceneRef.value?.canvasMap
  canvasMap?.clearSelectedFeature?.()
}

function buildListPoint(row = {}) {
  const longitude = Number(row.longitude)
  const latitude = Number(row.latitude)
  return {
    ...row,
    id: row.key || row.id,
    name: row.fullName || row.name,
    stageKey: row.stageKey,
    stageName: row.stageName || getStageDef(row.stageKey)?.name,
    categoryName: row.categoryName || row.typeName,
    capacity: row.value,
    capacityUnit: row.unit,
    longitude,
    latitude,
    geometry: Number.isFinite(longitude) && Number.isFinite(latitude)
      ? { type: "Point", coordinates: [longitude, latitude] }
      : undefined,
    status: row.status,
  }
}

function syncSelectedPointScreen(point, focusResult = null) {
  const screen = mapSceneRef.value?.getYakIndustryPointScreen?.(point) || focusResult?.screen
  if (screen) selectedPointScreen.value = normalizeFeatureScreen(screen)
}

function formatCapacity(point) {
  if (point.capacity === undefined || point.capacity === null || point.capacity === "") return ""
  return `${point.capacity}${point.capacityUnit || ""}`
}

function formatDisplayText(value) {
  return String(value ?? "")
    .replace(/\bcxpt[-_./\s]*/gi, "")
    .replace(/\s+/g, " ")
    .trim()
}

function normalizeFeatureScreen(screen = {}) {
  const root = document.querySelector("#large-screen")
  const rect = root?.getBoundingClientRect?.()
  const scaleX = rect?.width ? 1920 / rect.width : 1
  const scaleY = rect?.height ? 1080 / rect.height : 1
  const left = rect?.left || 0
  const top = rect?.top || 0
  return {
    x: (Number(screen.x) - left) * scaleX,
    y: (Number(screen.y) - top) * scaleY,
  }
}

</script>

<style lang="scss">
.yak-industry-chain {
  position: absolute;
  inset: 0;
  z-index: 1;
  overflow: hidden;
  color: #fff;
  background: #03121c;
}

.industry-map-scene {
  position: absolute;
  inset: 0;
  z-index: 1;
}

.industry-map-scrim {
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  background:
    radial-gradient(circle at 50% 48%, rgba(4, 18, 28, 0) 0%, rgba(4, 18, 28, 0.05) 37%, rgba(2, 10, 17, 0.34) 78%, rgba(1, 7, 12, 0.62) 100%),
    linear-gradient(90deg, rgba(0, 12, 20, 0.42), transparent 26%, transparent 74%, rgba(0, 12, 20, 0.42));
}

.industry-map-loading {
  position: absolute;
  left: 50%;
  top: 50%;
  z-index: 4;
  transform: translate(-50%, -50%);
  color: rgba(220, 250, 255, 0.78);
  font-size: 18px;
}

.industry-side-panel {
  position: absolute;
  top: 156px;
  bottom: 112px;
  z-index: 6;
  width: 398px;
  perspective: 700px;
  perspective-origin: 50% 50%;
  pointer-events: all;
}

.industry-side-panel--left {
  left: 32px;
}

.industry-side-panel--right {
  right: 32px;
}

.industry-side-stack {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  gap: 12px;
  transform-style: preserve-3d;

  &.is-left {
    transform: translate3d(0, 0, 0) rotateY(6deg);
    transform-origin: left center;
  }

  &.is-right {
    transform: translate3d(0, 0, 0) rotateY(-6deg);
    transform-origin: right center;
  }
}

.industry-side-card {
  flex: 0 0 auto;

  .m-card-bd-content {
    top: 40px;
    bottom: 10px;
    color: #f3feff;
    overflow: hidden;
  }

  .m-card-bd-bg {
    filter: brightness(1.08) saturate(1.04);
  }

  .m-card-bd-bg::after {
    content: "";
    position: absolute;
    inset: 4px 5px 6px;
    z-index: 0;
    pointer-events: none;
    border: 1px solid rgba(48, 220, 255, 0.14);
    background:
      linear-gradient(180deg, rgba(17, 73, 92, 0.16), rgba(6, 29, 44, 0.14)),
      linear-gradient(90deg, rgba(48, 220, 255, 0.1), transparent 42%, rgba(48, 220, 255, 0.06));
    box-shadow:
      inset 0 0 0 1px rgba(48, 220, 255, 0.06),
      inset 0 12px 28px rgba(48, 220, 255, 0.04);
  }
}

.industry-ledger-list {
  display: grid;
  gap: 7px;
}

.industry-ledger-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 10px;
  align-items: center;
  min-height: 42px;
  padding: 7px 8px;
  border: 1px solid rgba(48, 220, 255, 0.1);
  border-radius: 4px;
  background: rgba(4, 20, 31, 0.42);

  div {
    min-width: 0;
  }

  strong,
  span {
    display: block;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  strong {
    color: rgba(241, 254, 255, 0.92);
    font-size: 13px;
    font-weight: 760;
  }

  span {
    margin-top: 4px;
    color: rgba(201, 237, 244, 0.58);
    font-size: 11px;
  }

  em {
    color: #ffe06b;
    font-size: 12px;
    font-style: normal;
    font-weight: 800;
    white-space: nowrap;
  }
}

.industry-point-detail {
  position: absolute;
  z-index: 7;
  width: 430px;
  padding: 18px 20px 20px;
  border: 1px solid rgba(48, 220, 255, 0.42);
  background:
    linear-gradient(180deg, rgba(12, 54, 70, 0.86), rgba(5, 24, 37, 0.9)),
    radial-gradient(circle at 20% 0%, rgba(36, 246, 196, 0.18), transparent 46%);
  box-shadow:
    0 0 24px rgba(48, 220, 255, 0.18),
    inset 0 0 18px rgba(48, 220, 255, 0.08);
  color: #efffff;
  pointer-events: all;
}

.industry-point-detail::after {
  content: "";
  position: absolute;
  left: var(--point-arrow-side, 0);
  top: var(--point-arrow-top, 50%);
  width: 16px;
  height: 16px;
  border-right: 1px solid rgba(48, 220, 255, 0.42);
  border-bottom: 1px solid rgba(48, 220, 255, 0.42);
  background: rgba(5, 24, 37, 0.9);
  transform: translate(var(--point-arrow-offset, -9px), -50%) rotate(var(--point-arrow-rotate, 135deg));
}

.industry-point-detail__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  color: #ffe06b;
  font-size: 16px;
  font-weight: 700;

  button {
    width: 26px;
    height: 26px;
    border: 1px solid rgba(48, 220, 255, 0.36);
    border-radius: 0;
    background: rgba(6, 28, 43, 0.72);
    color: rgba(239, 255, 255, 0.88);
    cursor: pointer;
    font-size: 20px;
    line-height: 20px;
  }
}

.industry-point-detail__name {
  margin-top: 12px;
  color: #ffffff;
  font-size: 22px;
  font-weight: 800;
  line-height: 1.35;
}

.industry-point-detail__grid {
  display: grid;
  gap: 8px;
  margin-top: 14px;
}

.industry-point-detail__row {
  display: grid;
  grid-template-columns: 88px minmax(0, 1fr);
  gap: 12px;
  min-height: 32px;
  align-items: center;
  border-bottom: 1px solid rgba(48, 220, 255, 0.12);

  span {
    color: rgba(196, 237, 244, 0.74);
    font-size: 14px;
  }

  strong {
    overflow: hidden;
    color: rgba(246, 255, 255, 0.95);
    font-size: 15px;
    font-weight: 700;
    line-height: 1.35;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
}

.industry-bottom-switcher {
  position: absolute;
  left: 50%;
  bottom: 25px;
  z-index: 8;
  display: flex;
  align-items: center;
  justify-content: center;
  transform: translateX(-50%);
  pointer-events: all;

  .topic-switcher {
    width: 1060px;
  }

  .topic-switcher-item {
    width: var(--topic-item-width, 112px);
  }

  .topic-switcher-item .topic-name {
    font-size: 14px;
  }

  .topic-switcher-item .topic-title {
    font-size: 14px;
    line-height: 16px;
  }

  .topic-switcher-item .topic-name small {
    font-size: 10px;
    line-height: 11px;
  }
}
</style>
