<template>
  <div ref="chartRef" class="chart-container"></div>
</template>

<script>
import * as echarts from 'echarts';
import echartsResize from '@/mixins/echartsResize.js';

// 模块级共享定时器：所有实例订阅同一个 tick，保证扫描线完全同步
let sharedEpoch = 0;
let sharedTimer = null;
let sharedListeners = new Set();
let sharedBatchId = 0; // 批次ID，切换分页时递增

function joinSharedTimer(listener, batchId) {
  // 新批次：重置定时器和 epoch
  if (batchId !== sharedBatchId) {
    sharedBatchId = batchId;
    if (sharedTimer) { clearInterval(sharedTimer); sharedTimer = null; }
    sharedListeners.clear();
    sharedEpoch = Math.floor(Date.now() / 1000);
  }
  if (!sharedTimer) {
    sharedEpoch = Math.floor(Date.now() / 1000);
    sharedTimer = setInterval(() => {
      const elapsed = Math.floor(Date.now() / 1000) - sharedEpoch;
      sharedListeners.forEach(fn => fn(elapsed));
    }, 1000);
  }
  sharedListeners.add(listener);
  // 立即触发一次，避免 mounted 到首次 tick 之间的闪跳
  listener(Math.floor(Date.now() / 1000) - sharedEpoch);
}

function leaveSharedTimer(listener) {
  sharedListeners.delete(listener);
  if (sharedListeners.size === 0 && sharedTimer) {
    clearInterval(sharedTimer);
    sharedTimer = null;
    sharedEpoch = 0;
  }
}

const COLORS = {
  GREEN_LIGHT: '#8dc453', GREEN_DARK: '#73a542', YELLOW: '#fbd249', RED: '#ff7575', STRIPE_GREEN: '#a3d76e',
  TEXT_DARK: '#1e2638', AXIS_LINE: '#758599', DIVIDER_LINE: '#111827', MARK_BLUE: '#00E5FF', TEXT_LIGHT: '#d1d5db'
};

// 绘制条纹图案用于绿闪/预警
const stripeCanvas = document.createElement('canvas');
stripeCanvas.width = 6; stripeCanvas.height = 20;
const ctx = stripeCanvas.getContext('2d');
ctx.fillStyle = '#ffffff'; ctx.fillRect(0, 0, 6, 20);
ctx.fillStyle = COLORS.STRIPE_GREEN; ctx.fillRect(0, 0, 3, 20); 
const stripePattern = { image: stripeCanvas, repeat: 'repeat' };

const IMAGE_MAP = {
  'STRAIGHT_DOWN': require('@/assets/images/icon_straight_down.png'),
  'TURN_DOWN_LEFT': require('@/assets/images/icon_turn_down_left.png'),
  'TURN_DOWN_LEFT_UTURN': require('@/assets/images/icon_turn_down_left_uturn.png'),

  'STRAIGHT_UP': require('@/assets/images/icon_straight_up.png'),
  'TURN_UP_LEFT': require('@/assets/images/icon_turn_up_left.png'),
  'TURN_UP_LEFT_UTURN': require('@/assets/images/icon_turn_up_left_uturn.png'),

  'STRAIGHT_LEFT': require('@/assets/images/icon_straight_left.png'),
  'TURN_LEFT_DOWN': require('@/assets/images/icon_turn_left_down.png'),
  'TURN_LEFT_DOWN_UTURN': require('@/assets/images/icon_turn_left_down_uturn.png'), 

  'STRAIGHT_RIGHT': require('@/assets/images/icon_straight_right.png'),
  'TURN_RIGHT_UP': require('@/assets/images/icon_turn_right_up.png'),
  'TURN_RIGHT_UP_UTURN': require('@/assets/images/icon_turn_right_up_uturn.png' )
};

// ==========================================
// 核心逻辑：基于真实物理空间的对齐与自定义偏移/尺寸配置
// pos: 位置(LT/RT/LB/RB), padX/padY: 基础像素偏移, baseW/baseH: 基础原始宽高
// ==========================================
const POS_MAP = {
  // 1. 上方驶入 -> 靠左上角 (LT)
  'STRAIGHT_DOWN':         { pos: 'LT', padX: 10, padY: 0, baseW: 7, baseH: 20.67 },       
  'TURN_DOWN_LEFT':        { pos: 'LT', padX: 10, padY: 0, baseW: 13, baseH: 21.33 },      
  'TURN_DOWN_LEFT_UTURN':  { pos: 'LT', padX: 10, padY: 0, baseW: 13, baseH: 22.67 },
  
  // 2. 下方驶入 -> 靠右下角 (RB)
  'STRAIGHT_UP':           { pos: 'RB', padX: 10, padY: 0, baseW: 7, baseH: 20.67 },         
  'TURN_UP_LEFT':          { pos: 'RB', padX: 10, padY: 0, baseW: 13, baseH: 21.33 },        
  'TURN_UP_LEFT_UTURN':    { pos: 'RB', padX: 10, padY: 0, baseW: 13, baseH: 22.67 },
  
  // 3. 右侧驶入 -> 靠右上角 (RT)
  'STRAIGHT_LEFT':         { pos: 'RT', padX: 0, padY: 10, baseW: 20.33, baseH: 6.33 },       
  'TURN_LEFT_DOWN':        { pos: 'RT', padX: 0, padY: 10, baseW: 20.67, baseH: 12.33 },       
  'TURN_LEFT_DOWN_UTURN':  { pos: 'RT', padX: 0, padY: 10, baseW: 22.67, baseH: 12.33 },
  
  // 4. 左侧驶入 -> 靠左下角 (LB)
  'STRAIGHT_RIGHT':        { pos: 'LB', padX: 0, padY: 10, baseW: 20.33, baseH: 6.33 },
  'TURN_RIGHT_UP':         { pos: 'LB', padX: 0, padY: 10, baseW: 20.67, baseH: 12.33 },
  'TURN_RIGHT_UP_UTURN':   { pos: 'LB', padX: 0, padY: 10, baseW: 22.67, baseH: 12.33 },
};

export default {
  name: 'SignalTimingChart',
  mixins: [echartsResize],
  props: {
    cycleLength: { type: Number, default: 140 }, 
    currentTime: { type: Number, default: 0 },
    phaseData: { type: Array, default: () => [] },
    showAxis: { type: Boolean, default: true },
    showScanLine: { type: Boolean, default: true },
    showScanLineLabel: { type: Boolean, default: true },
    autoScan: { type: Boolean, default: false },
    syncScan: { type: Boolean, default: false }
  },
  data() {
    return { scaleFactor: 1, internalTime: 0 };
  },
  computed: {
    activeTime() {
      return this.autoScan ? this.internalTime : this.currentTime;
    }
  },
  mounted() {
    this.internalTime = this.currentTime;
    this.initChart();
    if (this.autoScan) this.startAutoScan();
  },
  beforeDestroy() {
    this.stopAutoScan();
  },
  watch: {
    currentTime(val) {
      if (!this.autoScan) {
        if (this.$_chart) this.updateScanLine();
      } else {
        // 页切换时 currentTime 变化，重新加入共享定时器触发 epoch 重置
        this.startAutoScan();
      }
    },
    autoScan(val) {
      if (val) { this.startAutoScan(); } else { this.stopAutoScan(); }
    },
    syncScan() {
      if (this.autoScan) { this.startAutoScan(); }
    },
    showScanLine(val) {
      this.updateChart();
      if (val && this.autoScan) { this.startAutoScan(); }
    },
    phaseData: { deep: true, handler(newVal) { if (this.$_chart && newVal.length > 0) this.updateChart(); } },
    showAxis() { this.updateChart(); },
    showScanLineLabel() { this.updateChart(); }
  },
  methods: {
    updateScale() {
      const el = this.$el;
      if (!el) return;
      this.scaleFactor = Math.max(0.5, el.clientWidth / 600);
    },
    startAutoScan() {
      this.stopAutoScan();
      const VISUAL_PERIOD = 120;
      if (this.syncScan) {
        // 共享定时器：所有行扫描线完全同步
        this._scanListener = (elapsed) => {
          const realMax = this.getMaxTime();
          const offset = this.currentTime || 0;
          const ratio = ((offset + elapsed) % VISUAL_PERIOD) / VISUAL_PERIOD;
          this.internalTime = ratio * realMax;
          if (this.$_chart) this.updateScanLine();
          this.$emit('scan-tick', this.internalTime);
        };
        joinSharedTimer(this._scanListener, this.currentTime || 0);
      } else {
        // 独立定时器：每行扫描线从 currentTime 位置开始独立移动
        this.internalTime = this.currentTime || 0;
        this._soloTimer = setInterval(() => {
          const realMax = this.getMaxTime();
          this.internalTime += 1;
          if (this.internalTime > realMax) this.internalTime = 0;
          if (this.$_chart) this.updateScanLine();
          this.$emit('scan-tick', this.internalTime);
        }, 1000);
      }
    },
    stopAutoScan() {
      if (this._scanListener) { leaveSharedTimer(this._scanListener); this._scanListener = null; }
      if (this._soloTimer) { clearInterval(this._soloTimer); this._soloTimer = null; }
    },
    initChart() {
      const chartDom = this.$refs.chartRef;
      if (!chartDom) return;
      this.updateScale();
      this.$_chart = echarts.init(chartDom);
      if (this.phaseData.length > 0) this.updateChart();
    },
    updateChart() {
      if (!this.$_chart) return;
      this.updateScale();
      this.$_chart.setOption(this.getChartOption(), true);
    },
    updateScanLine() {
      if (!this.$_chart) return;
      this.updateScale();
      const s = this.scaleFactor;
      const realMaxTime = this.getMaxTime();
      this.$_chart.setOption({
        series: [{
          markLine: !this.showScanLine ? false : {
            symbol: ['none', 'none'],
            silent: true,
            animation: false,
            label: {
              show: this.showScanLineLabel,
              position: 'start',
              formatter: `${Math.round(this.activeTime)}/${realMaxTime}`,
              color: '#fff', backgroundColor: COLORS.MARK_BLUE,
              padding: [Math.round(4 * s), Math.round(8 * s)],
              borderRadius: 2, fontSize: Math.max(10, Math.round(10 * s)),
              offset: [0, Math.round(1 * s)]
            },
            lineStyle: { color: COLORS.MARK_BLUE, type: 'solid', width: Math.max(2, Math.round(5 * s)), z: 100 },
            data: [{ xAxis: this.activeTime }]
          }
        }]
      });
    },
    getMaxTime() {
      if (!this.phaseData || this.phaseData.length === 0) return this.cycleLength;
      const maxDataTime = Math.max(...this.phaseData.map(item => item[2]));
      return Math.max(this.cycleLength, maxDataTime);
    },
    getChartOption() {
      const s = this.scaleFactor;
      const isTwoRows = this.phaseData.some(item => item[0] === 1);
      const yAxisData = isTwoRows ? ['Track 0', 'Track 1'] : ['Track 0'];
      const realMaxTime = this.getMaxTime();

      return {
        backgroundColor: 'transparent',
        grid: { 
          left: 0, right: 0, 
          // 当隐藏坐标轴/扫描线时（即在表格中显示时），将上下边距设为 0，让色块铺满高度
          top: (this.showAxis || this.showScanLineLabel) ? Math.round(35 * s) : 0, 
          bottom: (this.showAxis || this.showScanLineLabel) ? Math.round(10 * s) : 0,
          containLabel: false 
        },
        xAxis: { type: 'value', min: 0, max: realMaxTime, show: false },
        yAxis: { type: 'category', data: yAxisData, inverse: true, show: false },
        series: [{
          type: 'custom',
          renderItem: (params, api) => this.renderCustomItem(params, api, isTwoRows, realMaxTime),
          encode: { x: [1, 2], y: 0 },
          data: this.phaseData,
          markLine: !this.showScanLine ? false : {
            symbol: ['none', 'none'],
            silent: true,
            animation: false,
            label: {
              show: this.showScanLineLabel,
              position: 'start', formatter: `${Math.round(this.activeTime)}/${realMaxTime}`,
              color: '#fff', backgroundColor: COLORS.MARK_BLUE, padding: [Math.round(4 * s), Math.round(8 * s)],
              borderRadius: 2, fontSize: Math.max(10, Math.round(10 * s)),
              offset: [0, Math.round(1 * s)]
            },
            lineStyle: { color: COLORS.MARK_BLUE, type: 'solid', width: Math.max(2, Math.round(5 * s)), z: 100 },
            data: [ { xAxis: this.activeTime } ]
          }
        }]
      };
    },

    renderCustomItem(params, api, isTwoRows, realMaxTime) {
      const s = this.scaleFactor;
      const trackIndex = api.value(0);
      const start = api.coord([api.value(1), trackIndex]);
      const end = api.coord([api.value(2), trackIndex]);
      const blockHeight = api.size([0, 1])[1];
      const yPos = start[1] - blockHeight / 2;
      const blockWidth = end[0] - start[0];

      const phaseName = api.value(3);
      const duration = api.value(4);
      const type = api.value(5);
      const iconValue = api.value(6);

      let fillStyle = COLORS.GREEN_LIGHT;
      if (type === 'stripe') fillStyle = stripePattern;
      else if (type === 'yellow') fillStyle = COLORS.YELLOW;
      else if (type === 'red') fillStyle = COLORS.RED;

      const rectShape = echarts.graphic.clipRectByRect(
        { x: start[0], y: yPos, width: blockWidth, height: blockHeight },
        { x: params.coordSys.x, y: params.coordSys.y, width: params.coordSys.width, height: params.coordSys.height }
      );

      if (!rectShape) return;
      const children = [];

      // A. 绘制阶段刻度 (S1, S2...)
      if (params.dataIndex === 0 && this.showAxis) {
        const axisBaseY = params.coordSys.y - Math.round(15 * s);
        const track0Data = this.phaseData.filter(item => item[0] === 0);
        let stagePoints = track0Data.filter(item => item[5] === 'green').map(item => item[1]);
        if (!stagePoints.includes(0)) stagePoints.unshift(0);
        stagePoints.push(realMaxTime); 
        stagePoints = Array.from(new Set(stagePoints)).sort((a, b) => a - b);

        stagePoints.forEach(val => {
          const x = api.coord([val, 0])[0];
          children.push({ type: 'line', shape: { x1: x, y1: axisBaseY - Math.round(5 * s), x2: x, y2: axisBaseY + Math.round(5 * s) }, style: { stroke: COLORS.AXIS_LINE, lineWidth: Math.max(1, Math.round(1.5 * s)) } });
        });
        for (let i = 0; i < stagePoints.length - 1; i++) {
          const startX = api.coord([stagePoints[i], 0])[0];
          const endX = api.coord([stagePoints[i + 1], 0])[0];
          const midX = (startX + endX) / 2;
          const textHalf = Math.round(14 * s);
          children.push({ type: 'line', shape: { x1: startX, y1: axisBaseY, x2: midX - textHalf, y2: axisBaseY }, style: { stroke: COLORS.AXIS_LINE, lineWidth: Math.max(1, Math.round(1.5 * s)) } });
          children.push({ type: 'line', shape: { x1: midX + textHalf, y1: axisBaseY, x2: endX, y2: axisBaseY }, style: { stroke: COLORS.AXIS_LINE, lineWidth: Math.max(1, Math.round(1.5 * s)) } });
          children.push({ type: 'text', style: { text: `S${i + 1}`, x: midX, y: axisBaseY, fill: COLORS.TEXT_LIGHT, fontSize: Math.max(10, Math.round(14 * s)), align: 'center', verticalAlign: 'middle', fontWeight: 'bold' } });
        }
      }

      // B. 画色块背景
      children.push({ type: 'rect', shape: rectShape, style: { fill: fillStyle, stroke: 'none' } });

      // C. 绘制内部图标与文本
      // 提取基础缩放率
      const baseFs = Math.max(0.8, s * 0.9); 
      // 只要宽度大于 5 像素就尝试去渲染（原版限制是 > 15，改小以支持极限压缩）
      if (type === 'green' && blockWidth > 5) {
        
        // --- 1. 将 iconValue 统一解析为数组，提前判断需要多宽的背景 ---
        let iconList = [];
        if (Array.isArray(iconValue)) {
          iconList = iconValue;
        } else if (typeof iconValue === 'string' && iconValue.trim() !== '') {
          iconList = iconValue.split(',');
        } else if (iconValue) {
          iconList = [iconValue];
        }

        // 判断是否有靠左(LT/LB)和靠右(RT/RB)的图标
        let hasL = false, hasR = false;
        iconList.forEach(icon => {
          const valStr = String(icon).trim().toUpperCase();
          const posConfig = POS_MAP[valStr] || { pos: 'RB' };
          const pos = typeof posConfig === 'string' ? posConfig : (posConfig.pos || 'RB');
          if (pos.includes('L')) hasL = true;
          if (pos.includes('R')) hasR = true;
        });
        
        // 核心：动态赋予深绿色区域的基础宽度！
        // 如果左右都有图标，给46宽度；如果只有一侧有，收缩到28；啥都没给8
        let idealDarkWidthBase = (hasL && hasR) ? 46 : (iconList.length > 0 ? 28 : 0);
        if (idealDarkWidthBase === 0 && phaseName) idealDarkWidthBase = 8; 

        // 计算当前缩放下，理想状态需要的总像素宽度
        let idealDarkWidth = idealDarkWidthBase * baseFs;
        let idealTextWidth = 26 * baseFs; // 预留给 "P1\n24" 这类文本的宽度
        let totalNeededWidth = idealDarkWidth + 6 * baseFs + idealTextWidth;

        // --- 2. 计算动态弹性缩放率 (如果外部方块太小，内部按比例整体缩小) ---
        let innerScale = 1;
        if (blockWidth < totalNeededWidth) {
          // 最极限缩小到 15%，防止变成一个点引发渲染错误
          innerScale = Math.max(0.15, blockWidth / totalNeededWidth);
        }

        // 应用弹性缩放
        const dynamicFs = baseFs * innerScale;
        const darkWidth = idealDarkWidthBase * dynamicFs;
        const midY = yPos + blockHeight / 2;
        const pointerW = 4 * dynamicFs; // 中间那个小三角指针的大小也跟着缩放
        
        const innerGroup = {
          type: 'group',
          // 用 clipPath 限制死边界，防止文字或图标因为四舍五入溢出色块
          clipPath: { type: 'rect', shape: { x: start[0], y: yPos, width: blockWidth, height: blockHeight } },
          children: [
            { type: 'rect', shape: { x: start[0], y: yPos, width: darkWidth, height: blockHeight }, style: { fill: COLORS.GREEN_DARK } },
            { 
              type: 'polygon', 
              shape: { points: [ 
                [start[0] + darkWidth, midY - pointerW], 
                [start[0] + darkWidth, midY + pointerW], 
                [start[0] + darkWidth + pointerW, midY] 
              ] }, 
              style: { fill: COLORS.GREEN_DARK } 
            }
          ]
        };

        // --- 3. 绘制内部图标 ---
        iconList.forEach(icon => {
          const valStr = String(icon).trim().toUpperCase();
          const posConfig = POS_MAP[valStr] || { pos: 'RB', padX: 0, padY: 0, baseW: 20, baseH: 20 };
          const pos = typeof posConfig === 'string' ? posConfig : (posConfig.pos || 'RB');
          
          // 图标尺寸和边距也应用了 dynamicFs 动态缩放
          const drawW = Math.round((posConfig.baseW || 20) * dynamicFs);
          const drawH = Math.round((posConfig.baseH || 20) * dynamicFs);
          const padX = Math.round((posConfig.padX || 0) * dynamicFs); 
          const padY = Math.round((posConfig.padY || 0) * dynamicFs);

          let iconX, iconY;
          if (pos === 'LT') {
            iconX = start[0] + padX;
            iconY = yPos + padY;
          } else if (pos === 'RT') {
            iconX = start[0] + darkWidth - drawW - padX;
            iconY = yPos + padY;
          } else if (pos === 'LB') {
            iconX = start[0] + padX;
            iconY = yPos + blockHeight - drawH - padY;
          } else { // RB
            iconX = start[0] + darkWidth - drawW - padX;
            iconY = yPos + blockHeight - drawH - padY;
          }

          if (IMAGE_MAP[valStr]) {
            innerGroup.children.push({
              type: 'image',
              style: { 
                image: IMAGE_MAP[valStr], 
                x: iconX, 
                y: iconY, 
                width: drawW, 
                height: drawH,
                objectFit: 'contain' 
              }
            });
          }
        });
        
        // --- 4. 渲染右侧文字 (相位号与时长) ---
        // 彻底移除 8px 的硬性下限兜底，让字体完全跟随 dynamicFs 比例等比缩小
        const fontSize = Math.max(1, 12 * dynamicFs); 
        
        // 计算文本起点的X坐标
        const textStartX = start[0] + darkWidth + pointerW + (2 * dynamicFs);

        // 如果剩余空间大于 0（有哪怕一丁点空间），才进行文字渲染
        if (blockWidth > (darkWidth + pointerW + 2)) {
          innerGroup.children.push({
            type: 'text',
            style: {
              text: `${phaseName}\n${duration}`,
              x: textStartX,
              y: midY,
              fill: COLORS.TEXT_DARK,
              fontSize: fontSize,
              fontWeight: 'bold',
              align: 'left',
              verticalAlign: 'middle',
              // 行高也严格跟随动态字号
              lineHeight: fontSize * 1.2 
            }
          });
        }

        children.push(innerGroup);
      }
        
      // D. 轨道分割线 (仅在两排模式下 Track 1 顶部绘制)
      if (isTwoRows && trackIndex === 1) {
        const dividerY = (api.coord([0, 1])[1] + api.coord([0, 0])[1]) / 2;
        children.push({ type: 'line', shape: { x1: start[0], y1: dividerY, x2: end[0], y2: dividerY }, style: { stroke: COLORS.DIVIDER_LINE, lineWidth: Math.max(1, Math.round(1.5 * s)) } });
      }

      return { type: 'group', children: children };
    }
  }
};
</script>

<style scoped>
.chart-container { 
  width: 100%; height: 100%; flex: 1; min-height: 0; overflow: hidden;
}
</style>