<template>
  <div class="cesium-transition-wrapper">
    <div ref="cesiumContainer" class="cesium-container"></div>
    <div class="ui-layer">
      <div
        v-if="poi"
        ref="poiLabel"
        class="html-label"
        :style="{ color: poi.fontColor || '#00ffff', fontSize: (poi.fontSize || 20) + 'px', opacity: 0, display: 'none' }"
      >
        {{ poi.label }}
      </div>
    </div>
  </div>
</template>

<script>
import CesiumPreloader from '@/utils/cesiumPreloader';
const Cesium = window.Cesium;

function createOuterRingTexture(color) {
  const size = 1024, cx = size / 2, cy = size / 2, radius = size / 2 - 20;
  const lineWidth = 16, baseColorStr = color.toCssColorString();
  const canvas = document.createElement('canvas'); canvas.width = size; canvas.height = size; const ctx = canvas.getContext('2d');
  const solidCanvas = document.createElement('canvas'); solidCanvas.width = size; solidCanvas.height = size; const solidCtx = solidCanvas.getContext('2d'); solidCtx.lineWidth = lineWidth; solidCtx.strokeStyle = baseColorStr; solidCtx.shadowBlur = 10; solidCtx.shadowColor = baseColorStr; solidCtx.beginPath(); solidCtx.arc(cx, cy, radius, 0, Math.PI * 2); solidCtx.stroke();
  const dashedCanvas = document.createElement('canvas'); dashedCanvas.width = size; dashedCanvas.height = size; const dashedCtx = dashedCanvas.getContext('2d'); dashedCtx.lineWidth = lineWidth; dashedCtx.strokeStyle = baseColorStr; dashedCtx.setLineDash([12, 12]); dashedCtx.shadowBlur = 10; dashedCtx.shadowColor = baseColorStr; dashedCtx.beginPath(); dashedCtx.arc(cx, cy, radius, 0, Math.PI * 2); dashedCtx.stroke();
  const solidMask = ctx.createConicGradient(0, cx, cy); solidMask.addColorStop(0.0, 'rgba(0,0,0,0)'); solidMask.addColorStop(0.10, 'rgba(0,0,0,0)'); solidMask.addColorStop(0.18, 'rgba(0,0,0,1)'); solidMask.addColorStop(0.48, 'rgba(0,0,0,1)'); solidMask.addColorStop(0.50, 'rgba(0,0,0,0)'); solidMask.addColorStop(0.60, 'rgba(0,0,0,0)'); solidMask.addColorStop(0.68, 'rgba(0,0,0,1)'); solidMask.addColorStop(0.98, 'rgba(0,0,0,1)'); solidMask.addColorStop(1.0, 'rgba(0,0,0,0)');
  const dashedMask = ctx.createConicGradient(0, cx, cy); dashedMask.addColorStop(0.0, 'rgba(0,0,0,0)'); dashedMask.addColorStop(0.02, 'rgba(0,0,0,1)'); dashedMask.addColorStop(0.10, 'rgba(0,0,0,1)'); dashedMask.addColorStop(0.18, 'rgba(0,0,0,0)'); dashedMask.addColorStop(0.50, 'rgba(0,0,0,0)'); dashedMask.addColorStop(0.52, 'rgba(0,0,0,1)'); dashedMask.addColorStop(0.60, 'rgba(0,0,0,1)'); dashedMask.addColorStop(0.68, 'rgba(0,0,0,0)'); dashedMask.addColorStop(1.0, 'rgba(0,0,0,0)');
  ctx.drawImage(solidCanvas, 0, 0); ctx.globalCompositeOperation = 'destination-in'; ctx.fillStyle = solidMask; ctx.fillRect(0, 0, size, size);
  const tempCanvas = document.createElement('canvas'); tempCanvas.width = size; tempCanvas.height = size; const tempCtx = tempCanvas.getContext('2d'); tempCtx.drawImage(dashedCanvas, 0, 0); tempCtx.globalCompositeOperation = 'destination-in'; tempCtx.fillStyle = dashedMask; tempCtx.fillRect(0, 0, size, size);
  ctx.globalCompositeOperation = 'lighter'; ctx.drawImage(tempCanvas, 0, 0);
  ctx.globalCompositeOperation = 'destination-over'; ctx.shadowBlur = 40; ctx.shadowColor = color.withAlpha(0.3).toCssColorString(); ctx.strokeStyle = color.withAlpha(0.08).toCssColorString(); ctx.lineWidth = 20; ctx.beginPath(); ctx.arc(cx, cy, radius, 0, Math.PI * 2); ctx.stroke();
  return canvas.toDataURL();
}

function createScannerTexture(color) {
  const canvas = document.createElement('canvas'); canvas.width = 512; canvas.height = 512; const ctx = canvas.getContext('2d');
  const sharpColor = color.withAlpha(1.0).toCssColorString(); ctx.lineWidth = 3; ctx.strokeStyle = sharpColor; ctx.shadowBlur = 20; ctx.shadowColor = sharpColor; ctx.beginPath(); ctx.moveTo(256, 256); ctx.lineTo(506, 256); ctx.stroke(); return canvas.toDataURL();
}

function createLightBeamTexture(color) {
  const canvas = document.createElement('canvas'); canvas.width = 64; canvas.height = 256; const ctx = canvas.getContext('2d');
  const gradient = ctx.createLinearGradient(0, 256, 0, 0);
  gradient.addColorStop(0, color.withAlpha(0.6).toCssColorString()); gradient.addColorStop(0.4, color.withAlpha(0.1).toCssColorString()); gradient.addColorStop(1, color.withAlpha(0.0).toCssColorString());
  ctx.fillStyle = gradient; ctx.fillRect(0, 0, 64, 256); return canvas.toDataURL();
}

const TWO_PI = Math.PI * 2;

export default {
  name: 'CesiumTransition',
  props: {
    // 要高亮的省份名称
    province: {
      type: String,
      default: '北京市'
    },
    // 微观标记点（null 则不显示POI）
    poi: {
      type: Object,
      default: null
    },
    // 区域中心坐标 [lon, lat]（无POI时用于相机定位）
    districtCenter: {
      type: Array,
      default: null
    },
    // 路网数据
    roads: {
      type: Array,
      default: () => [
        { name: "阜石路-阜成路快速路", width: 12, glowPower: 0.3, color: '#00ffff', path: [[116.18, 39.93], [116.22, 39.93], [116.26, 39.928], [116.30, 39.925]] },
        { name: "石景山路-复兴路", width: 12, glowPower: 0.3, color: '#ff3333', path: [[116.18, 39.907], [116.224, 39.907], [116.25, 39.906], [116.30, 39.905]] },
        { name: "莲石东路快速路", width: 12, glowPower: 0.3, color: '#00ff00', path: [[116.18, 39.89], [116.22, 39.888], [116.26, 39.885], [116.30, 39.88]] },
        { name: "西五环路", width: 10, glowPower: 0.25, color: '#ffaa00', path: [[116.205, 39.95], [116.203, 39.92], [116.202, 39.89], [116.20, 39.86]] },
        { name: "玉泉路", width: 10, glowPower: 0.25, color: '#cc00ff', path: [[116.25, 39.94], [116.25, 39.907], [116.248, 39.88], [116.245, 39.86]] },
        { name: "西四环路", width: 10, glowPower: 0.25, color: '#ffff00', path: [[116.285, 39.94], [116.283, 39.91], [116.28, 39.88], [116.278, 39.85]] }
      ]
    },
    // 微观区域卫星底图
    satelliteImage: {
      type: Object,
      default: () => ({
        url: './beijing-satellite.jpg',
        bounds: [116.10, 39.80, 116.38, 39.98]  // [west, south, east, north]
      })
    },
    // 中国边界 GeoJSON 路径
    boundaryUrl: {
      type: String,
      default: './china.json'
    },
    // 微观俯冲视角高度(米)
    microViewRange: {
      type: Number,
      default: 10000
    }
  },
  data() {
    return {
      isAnimating: false
    };
  },
  mounted() {
    this._viewer = null;
    this._preRenderListener = null;
    this._chinaDataSource = null;
    this._chinaEffectsSource = null;
    this._microEffectsSource = null;
    this._macroAlpha = 0.0;
    this._destroyed = false;
    this._pendingTimers = [];

    this._coords = { start: [-15.0, 35.86, 45000000], china: [104.19, 35.86, 14000000] };

    this.$nextTick(async () => {
      if (!this.$refs.cesiumContainer) return;
      // 尝试复用预加载的 Viewer
      const preloaded = await CesiumPreloader.acquire(this.$refs.cesiumContainer);
      this.initCesium(preloaded);
      if (!preloaded) {
        await this.waitForGlobeReady();
      }
      if (!this._destroyed) this.startTransition();
    });
  },
  beforeDestroy() {
    this._destroyed = true;
    this._pendingTimers.forEach(id => clearTimeout(id));
    this._pendingTimers = [];
    if (this._viewer) {
      if (this._preRenderListener) {
        this._viewer.scene.preRender.removeEventListener(this._preRenderListener);
      }
      // Cesium destroy() 内部会 removeChild，但 Vue 可能已移除 DOM，需要先确保容器在文档中
      const cesiumWidget = this._viewer.cesiumWidget && this._viewer.cesiumWidget.container;
      if (cesiumWidget && !cesiumWidget.parentNode) {
        document.body.appendChild(cesiumWidget);
      }
      try {
        this._viewer.destroy();
      } catch (e) {
        // 忽略 DOM 已被 Vue 移除导致的 removeChild 错误
      }
      this._viewer = null;
    }
  },
  methods: {
    waitForGlobeReady() {
      return new Promise(resolve => {
        const startTime = Date.now();
        const maxWait = 3000; // 最多等待3秒，避免卡住
        const check = () => {
          if (this._destroyed) { resolve(); return; }
          if ((this._viewer && this._viewer.scene.globe.tilesLoaded) || (Date.now() - startTime > maxWait)) {
            resolve();
          } else {
            requestAnimationFrame(check);
          }
        };
        requestAnimationFrame(check);
      });
    },

    initCesium(preloadedViewer) {
      this._baseGold = Cesium.Color.GOLD;
      this._baseWhite = Cesium.Color.WHITE;
      this._baseBlack = Cesium.Color.BLACK;
      this._dynamicGold = this._baseGold.withAlpha(0);
      this._dynamicWhite = this._baseWhite.withAlpha(0);
      this._dynamicBlack = this._baseBlack.withAlpha(0);
      this._poiThemeColor = Cesium.Color.fromCssColorString(
        (this.poi && this.poi.themeColor) || '#00bfff'
      );

      // 将 props 中的 roads 转为 Cesium 颜色对象
      this._majorRoads = this.roads.map(r => ({
        ...r,
        color: Cesium.Color.fromCssColorString(r.color)
      }));

      if (preloadedViewer) {
        // 复用预加载的 Viewer（瓦片已渲染好）
        this._viewer = preloadedViewer;
      } else {
        // 降级：从头创建
        this._viewer = new Cesium.Viewer(this.$refs.cesiumContainer, {
          animation: false, timeline: false, baseLayerPicker: false, geocoder: false,
          homeButton: false, sceneModePicker: false, navigationHelpButton: false, infoBox: false,
          fullscreenButton: false, selectionIndicator: false, shadows: false, shouldAnimate: false,
          requestRenderMode: false,
          imageryProvider: new Cesium.UrlTemplateImageryProvider({
            url: './tiles/{z}/{y}/{x}.jpg',
            maximumLevel: 12
          })
        });

        this._viewer.cesiumWidget.creditContainer.style.display = "none";
      }

      const scene = this._viewer.scene;
      scene.fog.enabled = false;
      scene.skyAtmosphere.show = false;
      scene.globe.showGroundAtmosphere = false;
      scene.globe.enableLighting = true;
      scene.globe.tileCacheSize = 300;
      scene.globe.maximumScreenSpaceError = 1.5;

      this._viewer.clock.currentTime = Cesium.JulianDate.fromDate(new Date('2026-01-01T01:30:00Z'));
      this._viewer.clock.shouldAnimate = false;

      const baseLayer = this._viewer.imageryLayers.get(0);
      if (baseLayer) { 
        baseLayer.brightness = 0.75; // 亮度：1.0 是原图，小于 1.0 变暗，大于 1.0 变亮
        baseLayer.contrast = 1.3;    // 对比度
        baseLayer.gamma = 1; // 新增这一行：默认值是 1.0，调高可以显著提亮暗部环境
      }
      

      const cam = this._viewer.scene.screenSpaceCameraController;
      cam.enableRotate = false;
      cam.enableTranslate = false;
      cam.enableZoom = false;
      cam.enableTilt = false;
      cam.enableLook = false;

      // 微观区域高清卫星底图
      if (this.satelliteImage && this.satelliteImage.url) {
        const b = this.satelliteImage.bounds;
        this._viewer.imageryLayers.addImageryProvider(
          new Cesium.SingleTileImageryProvider({
            url: this.satelliteImage.url,
            rectangle: Cesium.Rectangle.fromDegrees(b[0], b[1], b[2], b[3])
          })
        );

        // 针对本地大图的专项优化
        this._viewer.scene.globe.maximumScreenSpaceError = 1.0; // 降低误差，强制渲染高清
        this._viewer.scene.globe.tileCacheSize = 200;           // 增加缓存

      }

      this._viewer.camera.setView({ destination: Cesium.Cartesian3.fromDegrees(...this._coords.start) });

      this.buildMacroLayer();
      this.buildMicroLayer();

      this._preRenderListener = this._viewer.scene.preRender.addEventListener(() => {
        if (!this._microEffectsSource || !this._microEffectsSource.show) return;

        // POI 标签跟踪
        if (this.poi && this.$refs.poiLabel && this.$refs.poiLabel.style.opacity !== "0") {
          const pos3D = Cesium.Cartesian3.fromDegrees(this.poi.lon, this.poi.lat);
          const screenPos = Cesium.SceneTransforms.wgs84ToWindowCoordinates(this._viewer.scene, pos3D);
          if (screenPos && screenPos.y > 0) {
            this.$refs.poiLabel.style.display = 'flex';
            this.$refs.poiLabel.style.left = screenPos.x + 'px';
            this.$refs.poiLabel.style.top = (screenPos.y - 150) + 'px';
          } else {
            this.$refs.poiLabel.style.display = 'none';
          }
        }

      });
    },

    buildMacroLayer() {
      this._chinaEffectsSource = new Cesium.CustomDataSource('chinaEffects');
      this._viewer.dataSources.add(this._chinaEffectsSource);
      this._chinaEffectsSource.show = false;

      Cesium.GeoJsonDataSource.load(this.boundaryUrl).then(ds => {
        if (this._destroyed) return;
        this._chinaDataSource = ds;

        const entities = ds.entities.values;
        const provinceMainLand = {};

        for (let i = 0; i < entities.length; i++) {
          const entity = entities[i];
          if (entity.polygon) {
            entity.polygon.fill = false;
            entity.polygon.outline = false;
            const positions = entity.polygon.hierarchy.getValue(Cesium.JulianDate.now()).positions;
            entity.polyline = new Cesium.PolylineGraphics({
              positions, width: 2,
              material: new Cesium.PolylineGlowMaterialProperty({
                glowPower: 0.05,
                color: new Cesium.CallbackProperty(() => this._dynamicGold, false)
              })
            });
            if (entity.name === this.province) {
              const pointCount = positions.length;
              if (!provinceMainLand[entity.name] || pointCount > provinceMainLand[entity.name].pointCount) {
                provinceMainLand[entity.name] = { pointCount, center: Cesium.BoundingSphere.fromPoints(positions).center };
              }
            }
          }
        }

        this._viewer.dataSources.add(ds);

        for (const name in provinceMainLand) {
          const mainCenter = provinceMainLand[name].center;
          this._chinaEffectsSource.entities.add({
            position: mainCenter,
            label: {
              text: name, font: 'bold 28px Microsoft YaHei',
              fillColor: new Cesium.CallbackProperty(() => this._dynamicWhite, false),
              outlineColor: new Cesium.CallbackProperty(() => this._dynamicBlack, false),
              outlineWidth: 3, style: Cesium.LabelStyle.FILL_AND_OUTLINE,
              heightReference: Cesium.HeightReference.RELATIVE_TO_GROUND,
              pixelOffset: new Cesium.Cartesian2(0, -10),
              distanceDisplayCondition: new Cesium.DistanceDisplayCondition(0, 20000000)
            }
          });
          for (let i = 0; i < 3; i++) {
            const offset = (4000 / 3) * i, startTime = Date.now() + offset;
            this._chinaEffectsSource.entities.add({
              position: mainCenter,
              ellipse: {
                semiMinorAxis: new Cesium.CallbackProperty(() => 350000 * (((Date.now() - startTime) % 4000) / 4000), false),
                semiMajorAxis: new Cesium.CallbackProperty(() => 350000 * (((Date.now() - startTime) % 4000) / 4000), false),
                material: new Cesium.ColorMaterialProperty(new Cesium.CallbackProperty(() => {
                  const t = ((Date.now() - startTime) % 4000) / 4000;
                  return Cesium.Color.DEEPSKYBLUE.withAlpha((1.0 - t) * 0.8 * this._macroAlpha);
                }, false)), height: 5000 + i * 100
              }
            });
          }
        }
      });
    },

    buildMicroLayer() {
      this._microEffectsSource = new Cesium.CustomDataSource('microEffects');
      this._viewer.dataSources.add(this._microEffectsSource);
      this._microEffectsSource.show = false;

      // POI 标记（可选）
      if (this.poi) {
        const pos3D = Cesium.Cartesian3.fromDegrees(this.poi.lon, this.poi.lat);
        const slowRingImg = createOuterRingTexture(this._poiThemeColor);
        const fastScannerImg = createScannerTexture(this._poiThemeColor);
        const beamImg = createLightBeamTexture(this._poiThemeColor);

        this._microEffectsSource.entities.add({ position: pos3D, ellipse: { semiMinorAxis: this.poi.radarRadius, semiMajorAxis: this.poi.radarRadius, material: new Cesium.ImageMaterialProperty({ image: slowRingImg, transparent: true }), stRotation: new Cesium.CallbackProperty(() => (Date.now() / 5000.0) % TWO_PI, false), height: 20 } });
        this._microEffectsSource.entities.add({ position: pos3D, ellipse: { semiMinorAxis: this.poi.radarRadius, semiMajorAxis: this.poi.radarRadius, material: new Cesium.ImageMaterialProperty({ image: fastScannerImg, transparent: true }), stRotation: new Cesium.CallbackProperty(() => (Date.now() / 300.0) % TWO_PI, false), height: 21 } });
        this._microEffectsSource.entities.add({ position: Cesium.Cartesian3.fromDegrees(this.poi.lon, this.poi.lat, 2000.0), cylinder: { length: 4000, topRadius: 20, bottomRadius: 200, material: new Cesium.ImageMaterialProperty({ image: beamImg, transparent: true }) } });
        this._microEffectsSource.entities.add({ position: Cesium.Cartesian3.fromDegrees(this.poi.lon, this.poi.lat, 50), point: { pixelSize: 15, color: Cesium.Color.WHITE, outlineColor: this._poiThemeColor, outlineWidth: 3 } });
      }

    },

    fadeMacroLayer(startAlpha, endAlpha, durationMs) {
      return new Promise(resolve => {
        if (startAlpha < endAlpha && this._chinaDataSource) {
          this._chinaDataSource.show = true;
          this._chinaEffectsSource.show = true;
        }
        const startTime = Date.now();
        const animateFade = () => {
          if (this._destroyed) { resolve(); return; }
          let p = (Date.now() - startTime) / durationMs; if (p >= 1.0) p = 1.0;
          this._macroAlpha = startAlpha + (endAlpha - startAlpha) * p;
          this._dynamicGold = this._baseGold.withAlpha(this._macroAlpha);
          this._dynamicWhite = this._baseWhite.withAlpha(this._macroAlpha);
          this._dynamicBlack = this._baseBlack.withAlpha(this._macroAlpha);
          if (p < 1.0) {
            requestAnimationFrame(animateFade);
          } else {
            if (endAlpha === 0 && this._chinaDataSource) {
              this._chinaDataSource.show = false;
              this._chinaEffectsSource.show = false;
            }
            resolve();
          }
        };
        requestAnimationFrame(animateFade);
      });
    },

    animatePathGrowing(roadObj, delayTime) {
      return new Promise(resolve => {
        const timerId = setTimeout(() => {
          if (this._destroyed) { resolve(); return; }
          const positions = roadObj.path.map(p => Cesium.Cartesian3.fromDegrees(p[0], p[1]));
          const distances = [0]; let totalLength = 0;
          for (let i = 1; i < positions.length; i++) {
            totalLength += Cesium.Cartesian3.distance(positions[i - 1], positions[i]);
            distances.push(totalLength);
          }
          let progress = 0.0, isFinished = false;

          this._microEffectsSource.entities.add({
            polyline: {
              positions: new Cesium.CallbackProperty(function () {
                if (isFinished) return positions;
                progress += 0.025;
                if (progress >= 1.0) { isFinished = true; resolve(); return positions; }
                const targetDist = progress * totalLength;
                const pts = [];
                for (let i = 1; i < positions.length; i++) {
                  pts.push(positions[i - 1]);
                  if (targetDist <= distances[i]) {
                    const seg = (targetDist - distances[i - 1]) / (distances[i] - distances[i - 1]);
                    const p = new Cesium.Cartesian3();
                    Cesium.Cartesian3.lerp(positions[i - 1], positions[i], seg, p);
                    pts.push(p); break;
                  }
                }
                return pts;
              }, false),
              width: roadObj.width,
              material: new Cesium.PolylineGlowMaterialProperty({ glowPower: roadObj.glowPower, color: roadObj.color })
            }
          });
        }, delayTime);
        this._pendingTimers.push(timerId);
      });
    },

    _safeDelay(ms) {
      return new Promise(resolve => {
        const id = setTimeout(resolve, ms);
        this._pendingTimers.push(id);
      });
    },

    async startTransition() {
      if (this.isAnimating) return;
      this.isAnimating = true;

      // 阶段1: 飞向中国 (2s)
      this._viewer.camera.flyTo({
        destination: Cesium.Cartesian3.fromDegrees(...this._coords.china), duration: 2
      });
      const fadeInId = setTimeout(() => {
        if (!this._destroyed) this.fadeMacroLayer(0.0, 1.0, 1000);
      }, 800);
      this._pendingTimers.push(fadeInId);

      await this._safeDelay(3000);
      if (this._destroyed) return;

      // 阶段2: 俯冲到微观
      const targetCenter = this.poi
        ? [this.poi.lon, this.poi.lat]
        : (this.districtCenter || [116.70, 39.80]);
      const targetSphere = Cesium.BoundingSphere.fromPoints([Cesium.Cartesian3.fromDegrees(targetCenter[0], targetCenter[1])]);
      this._viewer.camera.flyToBoundingSphere(targetSphere, {
        offset: new Cesium.HeadingPitchRange(0.0, Cesium.Math.toRadians(-45), this.microViewRange),
        duration: 2, easingFunction: Cesium.EasingFunction.CUBIC_IN_OUT
      });
      this.fadeMacroLayer(1.0, 0.0, 800);

      // 阶段3: 显示微观效果
      await this._safeDelay(1500);
      if (this._destroyed) return;
      this._microEffectsSource.show = true;
      if (this.poi && this.$refs.poiLabel) this.$refs.poiLabel.style.opacity = 1;

      await this._safeDelay(1000);
      if (this._destroyed) return;
      this.$emit('complete');
    }
  }
};
</script>

<style scoped>
.cesium-transition-wrapper {
  position: fixed;
  top: 0;
  left: 0;
  width: 100vw;
  height: 100vh;
  z-index: 9999;
  background: #020813;
  overflow: hidden;
  font-family: "Microsoft YaHei", sans-serif;
}

.cesium-container {
  width: 100%;
  height: 100%;
  margin: 0;
  padding: 0;
}

.ui-layer {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}

.html-label {
  position: absolute;
  padding: 4px 10px;
  border-radius: 2px;
  pointer-events: none;
  transition: opacity 0.5s;
  transform: translate(-50%, -100%);
  display: flex;
  flex-direction: column;
  align-items: center;
  white-space: nowrap;
  font-weight: bold;
  z-index: 5;
  border: 1px solid currentColor;
  background: rgba(0, 20, 30, 0.7);
  box-shadow: inset 0 0 10px currentColor;
  text-shadow: 0 0 5px #000;
}

.html-label::after {
  content: '';
  width: 2px;
  height: 35px;
  background: currentColor;
  margin-top: 5px;
  box-shadow: 0 0 5px currentColor;
}
</style>
