import type { EChartsType, EChartsOption } from 'echarts';
import {Decimal} from 'decimal.js';

interface DrawingLine {
  id: string;
  type: 'horizontal' | 'trend' | 'trendExtended';
  points: {
    xRatio: number;
    yValue: number;
    dataIndex?: number;
    date?: string;
  }[];
  style?: {
    color?: string;
    width?: number;
    type?: 'solid' | 'dashed';
  };
}

// 添加 ECharts X轴配置的类型定义
interface XAxisOption {
  data: string[];
}

// 在文件顶部添加 dataZoom 的类型定义
interface DataZoomOption {
  start?: number;
  end?: number;
  startValue?: number;
  endValue?: number;
}

// 首先修复类型定义
interface PreviewPoint {
  xRatio: number;
  yValue: number;
  dataIndex?: number;
}


export class ChartDrawingTools {
  private readonly chart: EChartsType;
  private readonly lines: Map<string, DrawingLine>;
  private isDrawing: boolean;
  private currentLineType: 'horizontal' | 'trend' | 'trendExtended' | null;
  private tempLine: DrawingLine | null;
  private canStartNewLine: boolean = true;
  private isTrendFirstPoint: boolean = false;

  constructor(chart: EChartsType) {
    this.chart = chart;
    this.lines = new Map();
    this.isDrawing = false;
    this.currentLineType = null;
    this.tempLine = null;

    this.bindEvents();
  }

  // 开始绘制
  public startDrawing(type: 'horizontal' | 'trend' | 'trendExtended'): void {
    this.isDrawing = true;
    this.currentLineType = type;
    this.canStartNewLine = true;
    this.isTrendFirstPoint = type === 'trend' || type === 'trendExtended';
  }

  // 停止绘制
  public stopDrawing(): void {
    this.isDrawing = false;
    this.currentLineType = null;
    this.tempLine = null;
    this.canStartNewLine = true;
    this.isTrendFirstPoint = false;
  }

  // 清除所有线条
  public clearAllLines(): void {
    this.lines.clear();
    this.updateChart();
  }

  // 删除指定线条
  public deleteLine(id: string): void {
    this.lines.delete(id);
    this.updateChart();
  }

  // 更新图表
  private updateChart(): void {
    const option = this.chart.getOption() as EChartsOption;
    const markLineData: any[] = [];
    const xAxis = (option.xAxis as XAxisOption[])[0];
    const dataZoom = (option.dataZoom as DataZoomOption[]) || [];
    const viewRange = {
      start: dataZoom[0]?.startValue ?? 0,
      end: dataZoom[0]?.endValue ?? (xAxis.data.length - 1)
    };
    const yRange = this.getYAxisRange();

    this.lines.forEach(line => {
      if (line.type === 'horizontal') {
        markLineData.push({
          yAxis: line.points[0].yValue,
          lineStyle: {
            color: line.type === 'trend' ? '#0000ff' : '#ff0000', // 趋势线蓝色，其他红色
            opacity: 1, // 透明度100%
            ...line.style,
            type: line.style?.type || 'solid'
          }
        });
      } else if (line.type === 'trend' && line.points.length === 2) {
        // 查找日期对应的索引
        const startIndex = xAxis.data.indexOf(line.points[0].date!);
        const endIndex = xAxis.data.indexOf(line.points[1].date!);
        
        // 只有当两个点的日期都能找到对应索引时才显示线条
        if (startIndex !== -1 && endIndex !== -1) {
          markLineData.push([{
            coord: [startIndex, line.points[0].yValue]
          }, {
            coord: [endIndex, line.points[1].yValue]
          }]);
        }
      } else if (line.type === 'trendExtended' && line.points.length === 2) {
        const startIndex = xAxis.data.indexOf(line.points[0].date!);
        const endIndex = xAxis.data.indexOf(line.points[1].date!);
        
        if (startIndex !== -1 && endIndex !== -1) {
          // 使用抽取的方法计算延伸线坐标
          const coords = this.calculateExtendedTrendLineCoords(
            { x: startIndex, y: line.points[0].yValue },
            { x: endIndex, y: line.points[1].yValue },
            viewRange,
            yRange
          );

          markLineData.push([{
            coord: [coords.left.x, coords.left.y],
            symbol: 'none',
            lineStyle: {
              color: '#0000ff', // 蓝色
              width: 1,
              type: 'solid'
            }
          }, {
            coord: [coords.right.x, coords.right.y],
            symbol: 'none',
            lineStyle: {
              color: '#0000ff', // 蓝色
              width: 1,
              type: 'solid'
            }
          }]);
        }
      }
    });

    const series = (option.series as any[]) || [];
    
    if (series[0]) {
      series[0].markLine = {
        animation: false,
        symbol: ['none', 'none'],
        lineStyle: {
          width: 1,
          type: 'solid'
        },
        data: markLineData
      };
    }

    this.chart.setOption({
      series: series
    }, { replaceMerge: ['series'] });
  }

  // 获取实际X轴坐标
  private getActualX(xRatio: number, xAxis: XAxisOption): number {
    const dataCount = xAxis.data.length;
    return Math.floor(xRatio * dataCount);
  }

  // 获取相对X轴位置
  private getXRatio(x: number, xAxis: XAxisOption): number {
    const dataCount = xAxis.data.length;
    return x / dataCount;
  }

  // 绑定事件处理器
  private bindEvents(): void {
    const zr = this.chart.getZr();

    zr.on('mousedown', (params: { offsetX: number; offsetY: number }) => {
      if (!this.isDrawing || !this.currentLineType || !this.canStartNewLine) return;

      // 如果是趋势线的第二个点，不创建新的 tempLine
      if (this.tempLine && !this.isTrendFirstPoint) return;

      const point = this.chart.convertFromPixel({ seriesIndex: 0 }, [
        params.offsetX,
        params.offsetY
      ]);

      if (!point) return;

      const option = this.chart.getOption() as EChartsOption;
      const xAxis = (option.xAxis as XAxisOption[])[0];
      const xRatio = this.getXRatio(point[0], xAxis);
      
      // 记录日期信息
      const dataIndex = Math.floor(point[0]);
      const date = xAxis.data[dataIndex];

      this.tempLine = {
        id: crypto.randomUUID(),
        type: this.currentLineType,
        points: [{
          xRatio,
          yValue: point[1],
          dataIndex,
          date
        }]
      };

      if (this.currentLineType === 'horizontal') {
        this.updatePreview();
      }
    });

    zr.on('mousemove', (params: { offsetX: number; offsetY: number }) => {
      if (!this.isDrawing || !this.tempLine) return;

      const point = this.chart.convertFromPixel({ seriesIndex: 0 }, [
        params.offsetX,
        params.offsetY
      ]);

      if (!point) return;

      const option = this.chart.getOption() as EChartsOption;
      const xAxis = (option.xAxis as XAxisOption[])[0];
      const xRatio = this.getXRatio(point[0], xAxis);
      const dataIndex = Math.floor(point[0]);  // 计算当前点的索引

      if (this.tempLine.type === 'horizontal') {
        this.tempLine.points = [{
          xRatio: 0,
          yValue: point[1]
        }];
        this.updatePreview();
      } else if (this.tempLine.type === 'trend' || this.tempLine.type === 'trendExtended') {
        if (this.tempLine.points.length > 0) {
          const previewPoints = [
            this.tempLine.points[0],
            {
              xRatio,
              yValue: point[1],
              dataIndex  // 添加 dataIndex
            }
          ];
          
          this.updatePreviewWithPoints(previewPoints);
        }
      }
    });

    zr.on('mouseup', (params: { offsetX: number; offsetY: number }) => {
      if (!this.isDrawing || !this.tempLine) return;

      if (this.tempLine.type === 'trend' || this.tempLine.type === 'trendExtended') {
        if (this.isTrendFirstPoint) {
          this.isTrendFirstPoint = false;
          return;
        }

        const point = this.chart.convertFromPixel({ seriesIndex: 0 }, [
          params.offsetX,
          params.offsetY
        ]);

        if (!point) return;

        const option = this.chart.getOption() as EChartsOption;
        const xAxis = (option.xAxis as XAxisOption[])[0];
        const xRatio = this.getXRatio(point[0], xAxis);
        
        // 记录第二个点的信息
        const dataIndex = Math.floor(point[0]);
        const date = xAxis.data[dataIndex];

        // 确保两个点不重合
        if (this.tempLine.points[0].xRatio === xRatio) {
          this.tempLine = null;
          return;
        }

        this.tempLine.points.push({
          xRatio,
          yValue: point[1],
          dataIndex,
          date
        });
      }

      this.lines.set(this.tempLine.id, this.tempLine);
      this.updateChart();
      const currentType = this.tempLine.type;
      this.tempLine = null;
      this.canStartNewLine = true;
      if (currentType === 'trend' || currentType === 'trendExtended') {
        this.isTrendFirstPoint = true;
      }
    });

    this.chart.on('datazoom', () => {
      this.updateChart();
    });

  }

  private getYAxisRange(): { min: number; max: number } {
    const option = this.chart.getOption();
    const dataZoom = (option.dataZoom as DataZoomOption[]) || [];
    const series = (option.series as any[])[0];
    
    // 获取当前视图范围
    const startIndex = dataZoom[0]?.startValue ?? 0;
    const endIndex = dataZoom[0]?.endValue ?? (series.data.length - 1);
    
    // 获取可见区域的数据
    const visibleData = series.data.slice(startIndex, endIndex + 1);
    
    // 计算可见区域的最大最小值
    let yMin = Infinity;
    let yMax = -Infinity;
    
    visibleData.forEach((item: any) => {
      const values = item.value || item;
      // K线数据格式为 [open, close, low, high]
      const low = parseFloat(values[2]);  // low
      const high = parseFloat(values[3]); // high
      
      if (!isNaN(low)) yMin = Math.min(yMin, low);
      if (!isNaN(high)) yMax = Math.max(yMax, high);
    });
    
    return {
      min: yMin,
      max: yMax
    };
  }
  

  // 添加新方法用于预览时的点更新
  private updatePreviewWithPoints(points: PreviewPoint[]): void {
    if (!this.tempLine) return;

    const option = this.chart.getOption() as EChartsOption;
    const xAxis = (option.xAxis as XAxisOption[])[0];
    const series = (option.series as any[]) || [];
    const currentSeries = series[0] || {};

    let previewData;
    
    if (this.tempLine.type === 'trend') {
      // 保持原有趋势线预览逻辑
      previewData = [
        {
          coord: [
            this.getActualX(points[0].xRatio, xAxis),
            points[0].yValue
          ]
        },
        {
          coord: [
            this.getActualX(points[1].xRatio, xAxis),
            points[1].yValue
          ]
        }
      ];
    } else if (this.tempLine.type === 'trendExtended') {
      const chartOption = this.chart.getOption();
      const dataZoom = (chartOption.dataZoom as DataZoomOption[]) || [];
      
      const viewStartIndex = dataZoom[0]?.startValue ?? 0;
      const viewEndIndex = dataZoom[0]?.endValue ?? (xAxis.data.length - 1);
      
      const actualStartX = this.getActualX(points[0].xRatio, xAxis);
      const actualStartY = points[0].yValue;
      const actualEndX = this.getActualX(points[1].xRatio, xAxis);
      const actualEndY = points[1].yValue;

      const { min, max } = this.getYAxisRange();

      // 使用抽取的方法计算延伸线坐标
      const coords = this.calculateExtendedTrendLineCoords(
        { x: actualStartX, y: actualStartY },
        { x: actualEndX, y: actualEndY },
        { start: viewStartIndex, end: viewEndIndex },
        { min, max }
      );

      previewData = [
        {
          coord: [coords.left.x, coords.left.y]
        },
        {
          coord: [coords.right.x, coords.right.y]
        }
      ];
    }

    if (previewData) {  // 只在有预览数据时更新
      this.chart.setOption({
        series: [{
          ...currentSeries,
          markLine: {
            animation: false,
            symbol: ['none', 'none'],
            lineStyle: {
              width: 1,
              type: 'dashed',
              color: '#ff0000', // 红色
              opacity: 1 // 透明度100%
            },
            data: [previewData]
          }
        }]
      }, { replaceMerge: ['series'] });
    }
  }

  // 更新预览线
  private updatePreview(): void {
    if (!this.tempLine) return;

    const option = this.chart.getOption() as EChartsOption;
    const previewData: any[] = [];

    if (this.tempLine.type === 'horizontal') {
      previewData.push({
        yAxis: this.tempLine.points[0].yValue,
        lineStyle: {
          type: 'dashed',
          color: '#ff0000', // 红色
          opacity: 1 // 透明度100%
        }
      });
    } else if (this.tempLine.points.length === 2) {
      const xAxis = (option.xAxis as XAxisOption[])[0];
      const start = this.getActualX(this.tempLine.points[0].xRatio, xAxis);
      const end = this.getActualX(this.tempLine.points[1].xRatio, xAxis);

      previewData.push([{
        coord: [start, this.tempLine.points[0].yValue]
      }, {
        coord: [end, this.tempLine.points[1].yValue]
      }]);
    }

    // 获取当前的系列配置
    const series = (option.series as any[]) || [];
    const currentSeries = series[0] || {};

    // 更新或添加 markLine 到现有系列
    this.chart.setOption({
      series: [{
        ...currentSeries,  // 保留现有系列的配置
        markLine: {
          animation: false,
          symbol: ['none', 'none'],
          lineStyle: {
            width: 1,
            type: 'dashed',
            color: '#ff0000', // 红色
            opacity: 1 // 透明度100%
          },
          data: previewData
        }
      }]
    }, { replaceMerge: ['series'] });
  }

  // 添加重绘线条的方法
  public redrawLines(): void {
    if (this.lines.size > 0) {
      this.updateChart();
    }
  }

  // 添加计算延伸趋势线坐标的方法
  private calculateExtendedTrendLineCoords(
    startPoint: { x: number; y: number },
    endPoint: { x: number; y: number },
    viewRange: { start: number; end: number },
    yRange: { min: number; max: number }
  ): { left: { x: number; y: number }; right: { x: number; y: number } } {
    // 计算斜率
    const slope = (endPoint.y - startPoint.y) / (endPoint.x - startPoint.x);
    
    // 计算左边延伸点
    let leftX = viewRange.start;
    let leftY = startPoint.y - slope * (startPoint.x - leftX);
    
    // 如果y值超出范围，锁定y到边界值并反推x
    if (leftY < yRange.min || leftY > yRange.max) {
      leftY = leftY < yRange.min ? yRange.min : yRange.max;
      leftX = startPoint.x - (startPoint.y - leftY) / slope;
    }
    
    // 计算右边延伸点
    let rightX = viewRange.end;
    let rightY = endPoint.y + slope * (rightX - endPoint.x);
    
    // 如果y值超出范围，锁定y到边界值并反推x
    if (rightY < yRange.min || rightY > yRange.max) {
      rightY = rightY < yRange.min ? yRange.min : yRange.max;
      rightX = endPoint.x + (rightY - endPoint.y) / slope;
    }

    return {
      left: { 
        x: Math.ceil(leftX), 
        y: leftY 
      },
      right: { 
        x: Math.ceil(rightX), 
        y: rightY 
      }
    };
  }
} 