<template>
  <div class="map-wrapper" ref="wrapper">
    <div class="konva-container" ref="konvaContainer"></div>
  </div>
</template>

<script>
import Konva from 'konva';

export default {
  name: 'IntersectionMap',
  props: {
    mapData: {
      type: Object,
      required: true
    }
  },
  data() {
    return {
      stage: null,
      layer: null,
      armsNodes: {}, 
      panelNodes: {}, 
      resizeObserver: null, 
      C: {
        BG: '#212842', ROAD: '#3d3938', YELLOW: '#D9A73D', WHITE: '#E0E0E0',
        SIGNAL_RED: '#FF5252', SIGNAL_GREEN: '#8DF582',
        PANEL_BG: 'rgba(30, 30, 40, 0.85)', BLUE: '#448AFF'
      },
      sizeConfig: {
        stageSize: 900, 
        laneWidth: 40,
        halfRoad: 160,
        roadWidth: 320,
        armLength: 350
      }
    };
  },
  mounted() {
    this.initKonvaStage();
    if (this.mapData && Object.keys(this.mapData).length > 0) {
      this.renderStaticConfig();
      this.updateDynamicSignals();
    }
    this.initResizeObserver();
  },
  beforeDestroy() {
    if (this.resizeObserver) {
      this.resizeObserver.disconnect();
    }
    if (this.stage) {
      this.stage.destroy();
    }
  },
  watch: {
    mapData: {
      handler(newData, oldData) {
        if (!newData) return;
        if (!oldData || JSON.stringify(newData.armsConfig) !== JSON.stringify(oldData.armsConfig)) {
          this.renderStaticConfig();
        }
        this.updateDynamicSignals();
      },
      deep: true
    }
  },
  methods: {
    initKonvaStage() {
      const { stageSize, halfRoad, roadWidth } = this.sizeConfig;
      const center = stageSize / 2;

      this.stage = new Konva.Stage({
        container: this.$refs.konvaContainer,
        width: stageSize,
        height: stageSize
      });
      this.layer = new Konva.Layer();
      this.stage.add(this.layer);

      this.layer.add(new Konva.Rect({ width: stageSize, height: stageSize, fill: this.C.BG }));
      this.layer.add(new Konva.Rect({ x: center - halfRoad, y: center - halfRoad, width: roadWidth, height: roadWidth, fill: this.C.ROAD }));

      this.armsNodes = {
        N: this.createRoadArm(center, center - halfRoad, 0),
        E: this.createRoadArm(center + halfRoad, center, 90),
        S: this.createRoadArm(center, center + halfRoad, 180),
        W: this.createRoadArm(center - halfRoad, center, 270)
      };
      Object.values(this.armsNodes).forEach(arm => this.layer.add(arm));

      this.createCenterPanel(center);
      this.layer.draw();
    },

    initResizeObserver() {
      this.resizeObserver = new ResizeObserver(() => {
        // 使用 requestAnimationFrame 防抖，让渲染更平滑
        window.requestAnimationFrame(() => {
          this.handleResize();
        });
      });
      if (this.$refs.wrapper) {
        this.resizeObserver.observe(this.$refs.wrapper);
      }
    },

    handleResize() {
      if (!this.stage || !this.$refs.wrapper) return;

      // 现在拿到的是纯粹的父容器尺寸，绝对不会被 Canvas 撑大
      const containerWidth = this.$refs.wrapper.clientWidth;
      const containerHeight = this.$refs.wrapper.clientHeight;

      // 如果容器被隐藏或没尺寸，则跳过
      if (containerWidth === 0 || containerHeight === 0) return;

      const scaleX = containerWidth / this.sizeConfig.stageSize;
      const scaleY = containerHeight / this.sizeConfig.stageSize;
      
      // 取宽和高中最小的缩放比，保证图形能完整显示在容器内且不变形
      const scale = Math.min(scaleX, scaleY);

      // 缩放舞台物理尺寸
      this.stage.width(this.sizeConfig.stageSize * scale);
      this.stage.height(this.sizeConfig.stageSize * scale);
      
      // 缩放内部虚拟坐标系
      this.stage.scale({ x: scale, y: scale });
    },

    createRoadArm(x, y, rotation) {
      const { halfRoad, roadWidth, laneWidth } = this.sizeConfig;
      const group = new Konva.Group({ x, y, rotation });
      
      group.add(new Konva.Rect({ x: -halfRoad, y: -350, width: roadWidth, height: 350, fill: this.C.ROAD }));
      group.add(new Konva.Line({ points: [0, -350, 0, -35], stroke: this.C.YELLOW, strokeWidth: 3 }));
      group.add(new Konva.Path({ data: `M -160 -350 L -160 -30 Q -160 0 -180 0`, stroke: this.C.YELLOW, strokeWidth: 3 }));
      group.add(new Konva.Path({ data: `M 160 -350 L 160 -30 Q 160 0 180 0`, stroke: this.C.YELLOW, strokeWidth: 3 }));
      group.add(new Konva.Line({ points: [-160, -35, 0, -35], stroke: this.C.WHITE, strokeWidth: 4 }));
      
      for (let i = 1; i < 4; i++) {
        let ox = i * laneWidth;
        group.add(new Konva.Line({ points: [-ox, -35, -ox, -120], stroke: this.C.WHITE, strokeWidth: 2 }));
        group.add(new Konva.Line({ points: [-ox, -120, -ox, -350], stroke: this.C.WHITE, strokeWidth: 2, dash: [15, 15] }));
        group.add(new Konva.Line({ points: [ox, -35, ox, -350], stroke: this.C.WHITE, strokeWidth: 2, dash: [15, 15] }));
      }
      
      const lightGroup = new Konva.Group();
      const rectOpts = { y: -16, width: 8, height: 24, cornerRadius: 2, offsetX: 4, offsetY: 12 };
      for (let lx = -148; lx <= -20; lx += 16) lightGroup.add(new Konva.Rect({ x: lx, ...rectOpts }));
      for (let rx = 20; rx <= 148; rx += 16) lightGroup.add(new Konva.Rect({ x: rx, ...rectOpts }));
      group.add(lightGroup);
      group.lightGroup = lightGroup;

      group.arrowNodes = { 0: null, 1: null, 2: null, 3: null };
      group.cameraNode = null;

      return group;
    },

    createCenterPanel(center) {
      const panelGroup = new Konva.Group({ x: center - 80, y: center - 45 });
      panelGroup.add(new Konva.Rect({ width: 160, height: 90, fill: this.C.PANEL_BG, cornerRadius: 8 }));
      
      const labelFont = { fontSize: 18, fontFamily: 'monospace', fontStyle: 'bold', fill: this.C.WHITE }; 
      const valueFont = { fontSize: 28, fontFamily: 'monospace', fontStyle: 'bold' };              
      
      this.panelNodes.nsLabel = new Konva.Text({ ...labelFont, x: 15, y: 22, text: '相位-:' });
      this.panelNodes.nsVal = new Konva.Text({ ...valueFont, x: 90, y: 15, text: '--', fill: this.C.SIGNAL_GREEN });
      
      this.panelNodes.ewLabel = new Konva.Text({ ...labelFont, x: 15, y: 55, text: '相位-:' });
      this.panelNodes.ewVal = new Konva.Text({ ...valueFont, x: 90, y: 48, text: '--', fill: this.C.SIGNAL_GREEN });
      
      panelGroup.add(this.panelNodes.nsLabel, this.panelNodes.nsVal, this.panelNodes.ewLabel, this.panelNodes.ewVal);
      this.layer.add(panelGroup);
    },

    createArrowIcon(type, x, y, color = this.C.WHITE) {
      const group = new Konva.Group({ x, y, scaleX: 0.65, scaleY: 0.65 });
      group.add(new Konva.Circle({ x: 0, y: -35, radius: 3, fill: color, name: 'colorFill' }));
      let pathData = '';
      if (type === 'S') pathData = 'M 0 -35 L 0 0 M -7 -10 L 0 0 L 7 -10';
      else if (type === 'L') pathData = 'M 0 -35 L 0 -15 Q 0 0 15 0 M 5 -7 L 15 0 L 5 7';
      else if (type === 'R') pathData = 'M 0 -35 L 0 -15 Q 0 0 -15 0 M -5 -7 L -15 0 L -5 7';
      else if (type === 'U') pathData = 'M 0 -35 L 0 -15 Q 0 0 14 0 Q 28 0 28 -15 L 28 -25 M 21 -18 L 28 -25 L 35 -18';
      group.add(new Konva.Path({ data: pathData, stroke: color, strokeWidth: 3, lineCap: 'round', lineJoin: 'round', name: 'colorStroke' }));
      return group;
    },

    createCameraIcon(type, x, y) {
      const group = new Konva.Group({ x, y });
      if (type === 1) { 
        group.add(new Konva.Line({ points: [-16, -30, 16, -30], stroke: this.C.BLUE, strokeWidth: 2.5, lineCap: 'round' }));
        group.add(new Konva.Line({ points: [0, -30, 0, -10], stroke: this.C.BLUE, strokeWidth: 2.5 }));
        const body = new Konva.Group({ y: -10, rotation: 15 });
        body.add(new Konva.Rect({ x: -16, y: -8, width: 32, height: 16, stroke: this.C.BLUE, strokeWidth: 2.5, cornerRadius: 2 }));
        body.add(new Konva.Rect({ x: 16, y: -4, width: 6, height: 8, stroke: this.C.BLUE, strokeWidth: 2.5, cornerRadius: 1 }));
        group.add(body);
      } else if (type === 2) { 
        group.add(new Konva.Rect({ x: -14, y: -24, width: 28, height: 24, stroke: this.C.BLUE, strokeWidth: 2.5, cornerRadius: 6 }));
        group.add(new Konva.Circle({ x: 0, y: -12, radius: 5, stroke: this.C.BLUE, strokeWidth: 2.5 }));
        group.add(new Konva.Line({ points: [-10, 0, 10, 0], stroke: this.C.BLUE, strokeWidth: 2.5, lineCap: 'round' }));
        group.add(new Konva.Line({ points: [0, 0, 0, 6], stroke: this.C.BLUE, strokeWidth: 2.5 }));
      }
      return group;
    },

    renderStaticConfig() {
      const config = this.mapData.armsConfig;
      if (!config) return;

      Object.keys(config).forEach(dir => {
        const armData = config[dir];
        const armNode = this.armsNodes[dir];

        if (armNode.cameraNode) armNode.cameraNode.destroy();
        if (armData.cameraType > 0) {
          const cam = this.createCameraIcon(armData.cameraType, -80, -190);
          armNode.add(cam);
          armNode.cameraNode = cam;
        }

        armData.lanes.forEach((type, index) => {
          if (armNode.arrowNodes[index]) armNode.arrowNodes[index].destroy();
          if (type) {
            const lx = -20 - (index * this.sizeConfig.laneWidth);
            const arrow = this.createArrowIcon(type, lx, -80, this.C.WHITE);
            armNode.add(arrow);
            armNode.arrowNodes[index] = arrow;
          }
        });
      });
      this.layer.draw();
    },

    updateDynamicSignals() {
      const signals = this.mapData.signals;
      if (!signals) return;

      const nsColor = signals.ns.isGreen ? this.C.SIGNAL_GREEN : this.C.SIGNAL_RED;
      const ewColor = signals.ew.isGreen ? this.C.SIGNAL_GREEN : this.C.SIGNAL_RED;

      const dyeArm = (armNode, color) => {
        armNode.lightGroup.getChildren().forEach(r => r.fill(color));
        Object.values(armNode.arrowNodes).forEach(arr => {
          if (arr) {
            arr.findOne('.colorFill').fill(color);
            arr.findOne('.colorStroke').stroke(color);
          }
        });
      };

      dyeArm(this.armsNodes.N, nsColor);
      dyeArm(this.armsNodes.S, nsColor);
      dyeArm(this.armsNodes.E, ewColor);
      dyeArm(this.armsNodes.W, ewColor);

      this.panelNodes.nsLabel.text(`${signals.ns.phaseName}:`);
      this.panelNodes.nsVal.text(signals.ns.time.toString().padStart(2, '0')).fill(nsColor);
      
      this.panelNodes.ewLabel.text(`${signals.ew.phaseName}:`);
      this.panelNodes.ewVal.text(signals.ew.time.toString().padStart(2, '0')).fill(ewColor);

      this.layer.draw();
    }
  }
};
</script>

<style scoped>
/* 定义外层包裹容器 */
.map-wrapper {
  width: 100%;
  height: 100%;
  overflow: hidden;
  background-color: #212842;
  position: relative; /* 让内部绝对定位元素以此为参考 */
}
.konva-container {
  position: absolute; /* 必须有，让 Canvas 脱离文档流 */
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}
</style>