/**
 * 通用绘制函数
 *
 * 从 u-charts 核心库搬迁的通用绘制相关函数
 * 用于处理数据点形状、工具提示等通用绘制操作
 */
// @ts-nocheck - 由于从 u-charts 搬迁，类型系统不兼容，暂时禁用类型检查

import type { ChartOptions, UChartsConfig } from '../data-processing/series-calculator';
import { measureText } from '../utils/text';
import { convertCoordinateOrigin } from '../utils/coordinate';
import { avoidCollision } from '../utils/collision';
import { hexToRgb } from '../utils/color';
import { assign } from '../config';

// Canvas 上下文类型（使用 any 以兼容小程序环境）
export type CanvasContext = any;

/**
 * 坐标点接口
 */
export interface Point {
  x: number;
  y: number;
}

/**
 * 工具提示文本项接口
 */
export interface ToolTipTextItem {
  text: string | number;
  color?: string | null;
  legendShape?: string;
}

/**
 * 工具提示选项接口
 */
export interface ToolTipOption {
  group?: number[];
  index?: number | number[];
  offset?: Point;
  textList?: ToolTipTextItem[];
  horizentalLine?: boolean;
  xAxisLabel?: boolean;
  yAxisLabel?: boolean;
  gridType?: string;
  gridColor?: string;
  dashLength?: number;
  labelBgColor?: string;
  labelBgOpacity?: number;
  labelFontColor?: string;
  showBox?: boolean;
  showArrow?: boolean;
  showCategory?: boolean;
  bgColor?: string;
  bgOpacity?: number;
  borderColor?: string;
  borderWidth?: number;
  borderRadius?: number;
  borderOpacity?: number;
  boxPadding?: number;
  fontColor?: string;
  fontSize?: number;
  lineHeight?: number;
  legendShow?: boolean;
  legendShape?: string;
  splitLine?: boolean;
  activeBgColor?: string;
  activeBgOpacity?: number;
  activeWidth?: number;
  [key: string]: any;
}

/**
 * 标记线数据项接口
 */
export interface MarkLineDataItem {
  value: number;
  y: number;
  labelText?: string;
  lineColor?: string;
  showLabel?: boolean;
  labelFontSize?: number;
  labelPadding?: number;
  labelFontColor?: string;
  labelBgColor?: string;
  labelBgOpacity?: number;
  labelAlign?: string;
  labelOffsetX?: number;
  labelOffsetY?: number;
  type?: string;
  dashLength?: number;
  data?: MarkLineDataItem[];
  [key: string]: any;
}

/**
 * 激活点选项接口
 */
export interface ActivePointOption {
  activeType?: string;
  [key: string]: any;
}

/**
 * 标题选项接口
 */
export interface TitleOption {
  name?: string;
  fontSize?: number;
  color?: string;
  offsetX?: number;
  offsetY?: number;
}

/**
 * 计算标记线数据
 * @param data - 标记线数据数组
 * @param opts - 图表配置选项
 * @returns 计算后的标记线数据数组
 */
function calMarkLineData(data: MarkLineDataItem[], opts: ChartOptions): MarkLineDataItem[] {
  const points: MarkLineDataItem[] = [];
  const spacingValid = opts.height! - opts.area![0] - opts.area![2];
  const minRange = opts.chartData?.yAxisData?.ranges?.[0]?.[0] || 0;
  const maxRange = opts.chartData?.yAxisData?.ranges?.[0]?.[1] || 0;

  for (let i = 0; i < data.length; i++) {
    const item = data[i];
    const y = opts.height! - Math.round(spacingValid * (item.value - minRange) / (maxRange - minRange)) - opts.area![2];
    points.push({ ...item, y });
  }
  return points;
}

/**
 * 计算工具提示Y轴数据
 * @param offsetY - Y轴偏移量
 * @param series - 系列数据数组
 * @param opts - 图表配置选项
 * @param config - uCharts配置对象
 * @param eachSpacing - 每个数据点的间距
 * @returns Y轴标签文本数组
 */
function calTooltipYAxisData(
  offsetY: number,
  series: any[],
  opts: ChartOptions,
  config: UChartsConfig,
  eachSpacing: number
): string[] {
  const yAxisData = opts.chartData?.yAxisData;
  if (!yAxisData) return [];

  const ranges = yAxisData.ranges || [];
  const result: string[] = [];

  for (let i = 0; i < ranges.length; i++) {
    const range = ranges[i];
    const minRange = range[0];
    const maxRange = range[1];
    const yAxisItem = opts.yAxis?.data?.[i];

    if (maxRange === undefined || minRange === undefined) continue;

    const spacingValid = opts.height! - opts.area![0] - opts.area![2];
    const value = maxRange - (opts.height! - opts.area![2] - offsetY) * (maxRange - minRange) / spacingValid;

    let labelText = String(value);
    if (yAxisItem?.formatter) {
      labelText = yAxisItem.formatter(value, i, opts);
    } else if (opts.yAxis?.formatter) {
      labelText = opts.yAxis.formatter(value, i, opts);
    }

    result.push(labelText);
  }

  return result;
}

/**
 * 绘制数据点形状
 * @param points - 数据点坐标数组
 * @param color - 填充颜色
 * @param shape - 点形状 ('diamond', 'circle', 'square', 'triangle', 'none')
 * @param context - Canvas 渲染上下文
 * @param opts - 图表配置选项
 */
export function drawPointShape(
  points: (Point | null)[],
  color: string,
  shape: string,
  context: CanvasContext,
  opts: ChartOptions
): void {
  context.beginPath();
  if (opts.dataPointShapeType === 'hollow') {
    context.setStrokeStyle(color);
    context.setFillStyle(opts.background);
    context.setLineWidth(2 * opts.pix);
  } else {
    context.setStrokeStyle("#ffffff");
    context.setFillStyle(color);
    context.setLineWidth(1 * opts.pix);
  }
  if (shape === 'diamond') {
    points.forEach(function(item) {
      if (item !== null) {
        context.moveTo(item.x, item.y - 4.5);
        context.lineTo(item.x - 4.5, item.y);
        context.lineTo(item.x, item.y + 4.5);
        context.lineTo(item.x + 4.5, item.y);
        context.lineTo(item.x, item.y - 4.5);
      }
    });
  } else if (shape === 'circle') {
    points.forEach(function(item) {
      if (item !== null) {
        context.moveTo(item.x + 2.5 * opts.pix, item.y);
        context.arc(item.x, item.y, 3 * opts.pix, 0, 2 * Math.PI, false);
      }
    });
  } else if (shape === 'square') {
    points.forEach(function(item) {
      if (item !== null) {
        context.moveTo(item.x - 3.5, item.y - 3.5);
        context.rect(item.x - 3.5, item.y - 3.5, 7, 7);
      }
    });
  } else if (shape === 'triangle') {
    points.forEach(function(item) {
      if (item !== null) {
        context.moveTo(item.x, item.y - 4.5);
        context.lineTo(item.x - 4.5, item.y + 4.5);
        context.lineTo(item.x + 4.5, item.y + 4.5);
        context.lineTo(item.x, item.y - 4.5);
      }
    });
  } else if (shape === 'none') {
    return;
  }
  context.closePath();
  context.fill();
  context.stroke();
}

/**
 * 绘制激活数据点
 * @param points - 数据点坐标数组
 * @param color - 填充颜色
 * @param shape - 点形状
 * @param context - Canvas 渲染上下文
 * @param opts - 图表配置选项
 * @param option - 激活点选项
 * @param seriesIndex - 系列索引
 */
export function drawActivePoint(
  points: (Point | null)[],
  color: string,
  shape: string,
  context: CanvasContext,
  opts: ChartOptions,
  option: ActivePointOption,
  seriesIndex: number
): void {
  if (!opts.tooltip) {
    return;
  }
  if (opts.tooltip.group && opts.tooltip.group.length > 0 && opts.tooltip.group.includes(seriesIndex) === false) {
    return;
  }
  const pointIndex = typeof opts.tooltip.index === 'number'
    ? opts.tooltip.index
    : opts.tooltip.index![opts.tooltip.group.indexOf(seriesIndex)];

  context.beginPath();
  if (option.activeType === 'hollow') {
    context.setStrokeStyle(color);
    context.setFillStyle(opts.background);
    context.setLineWidth(2 * opts.pix);
  } else {
    context.setStrokeStyle("#ffffff");
    context.setFillStyle(color);
    context.setLineWidth(1 * opts.pix);
  }

  if (shape === 'diamond') {
    points.forEach(function(item, index) {
      if (item !== null && pointIndex === index) {
        context.moveTo(item.x, item.y - 4.5);
        context.lineTo(item.x - 4.5, item.y);
        context.lineTo(item.x, item.y + 4.5);
        context.lineTo(item.x + 4.5, item.y);
        context.lineTo(item.x, item.y - 4.5);
      }
    });
  } else if (shape === 'circle') {
    points.forEach(function(item, index) {
      if (item !== null && pointIndex === index) {
        context.moveTo(item.x + 2.5 * opts.pix, item.y);
        context.arc(item.x, item.y, 3 * opts.pix, 0, 2 * Math.PI, false);
      }
    });
  } else if (shape === 'square') {
    points.forEach(function(item, index) {
      if (item !== null && pointIndex === index) {
        context.moveTo(item.x - 3.5, item.y - 3.5);
        context.rect(item.x - 3.5, item.y - 3.5, 7, 7);
      }
    });
  } else if (shape === 'triangle') {
    points.forEach(function(item, index) {
      if (item !== null && pointIndex === index) {
        context.moveTo(item.x, item.y - 4.5);
        context.lineTo(item.x - 4.5, item.y + 4.5);
        context.lineTo(item.x + 4.5, item.y + 4.5);
        context.lineTo(item.x, item.y - 4.5);
      }
    });
  } else if (shape === 'none') {
    return;
  }
  context.closePath();
  context.fill();
  context.stroke();
}

/**
 * 绘制环形图标题
 * @param opts - 图表配置选项
 * @param config - uCharts配置对象
 * @param context - Canvas 渲染上下文
 * @param center - 中心点坐标
 */
export function drawRingTitle(
  opts: ChartOptions,
  config: UChartsConfig,
  context: CanvasContext,
  center: Point
): void {
  const titlefontSize = opts.title?.fontSize || config.titleFontSize;
  const subtitlefontSize = opts.subtitle?.fontSize || config.subtitleFontSize;
  const title = opts.title?.name || '';
  const subtitle = opts.subtitle?.name || '';
  const titleFontColor = opts.title?.color || opts.fontColor;
  const subtitleFontColor = opts.subtitle?.color || opts.fontColor;
  const titleHeight = title ? titlefontSize : 0;
  const subtitleHeight = subtitle ? subtitlefontSize : 0;
  const margin = 5;

  if (subtitle) {
    const textWidth = measureText(subtitle, subtitlefontSize * opts.pix, context);
    const startX = center.x - textWidth / 2 + (opts.subtitle?.offsetX || 0) * opts.pix;
    const startY = center.y + subtitlefontSize * opts.pix / 2 + (opts.subtitle?.offsetY || 0) * opts.pix;
    const finalStartY = title ? startY + (titleHeight * opts.pix + margin) / 2 : startY;

    context.beginPath();
    context.setFontSize(subtitlefontSize * opts.pix);
    context.setFillStyle(subtitleFontColor);
    context.fillText(subtitle, startX, finalStartY);
    context.closePath();
    context.stroke();
  }

  if (title) {
    const _textWidth = measureText(title, titlefontSize * opts.pix, context);
    const _startX = center.x - _textWidth / 2 + (opts.title?.offsetX || 0);
    let _startY = center.y + titlefontSize * opts.pix / 2 + (opts.title?.offsetY || 0) * opts.pix;
    if (subtitle) {
      _startY -= (subtitleHeight * opts.pix + margin) / 2;
    }
    context.beginPath();
    context.setFontSize(titlefontSize * opts.pix);
    context.setFillStyle(titleFontColor);
    context.fillText(title, _startX, _startY);
    context.closePath();
    context.stroke();
  }
}

/**
 * 绘制数据点文本
 * @param points - 数据点坐标数组
 * @param series - 系列数据
 * @param config - uCharts配置对象
 * @param context - Canvas 渲染上下文
 * @param opts - 图表配置选项
 */
export function drawPointText(
  points: (Point | null)[],
  series: any,
  config: UChartsConfig,
  context: CanvasContext,
  opts: ChartOptions
): void {
  const data = series.data;
  const textOffset = series.textOffset || 0;

  points.forEach(function(item, index) {
    if (item !== null) {
      context.beginPath();
      const fontSize = series.textSize ? series.textSize * opts.pix : config.fontSize;
      context.setFontSize(fontSize);
      context.setFillStyle(series.textColor || opts.fontColor);

      let value = data[index];
      if (typeof data[index] === 'object' && data[index] !== null) {
        if (Array.isArray(data[index])) {
          value = data[index][1];
        } else {
          value = data[index].value;
        }
      }

      const formatVal = series.formatter ? series.formatter(value, index, series, opts) : value;
      context.setTextAlign('center');
      context.fillText(String(formatVal), item.x, item.y - 4 + textOffset * opts.pix);
      context.closePath();
      context.stroke();
      context.setTextAlign('left');
    }
  });
}

/**
 * 绘制工具提示分割线
 * @param offsetX - X轴偏移量
 * @param opts - 图表配置选项
 * @param config - uCharts配置对象
 * @param context - Canvas 渲染上下文
 */
export function drawToolTipSplitLine(
  offsetX: number,
  opts: ChartOptions,
  config: UChartsConfig,
  context: CanvasContext
): void {
  const toolTipOption = opts.extra?.tooltip || {};
  const gridType = toolTipOption.gridType === undefined ? 'solid' : toolTipOption.gridType;
  const dashLength = toolTipOption.dashLength === undefined ? 4 : toolTipOption.dashLength;

  const startY = opts.area![0];
  const endY = opts.height! - opts.area![2];

  if (gridType === 'dash') {
    context.setLineDash([dashLength, dashLength]);
  }

  context.setStrokeStyle(toolTipOption.gridColor || '#cccccc');
  context.setLineWidth(1 * opts.pix);
  context.beginPath();
  context.moveTo(offsetX, startY);
  context.lineTo(offsetX, endY);
  context.stroke();
  context.setLineDash([]);

  if (toolTipOption.xAxisLabel && opts.categories && opts.tooltip?.index !== undefined) {
    const labelText = String(opts.categories[opts.tooltip.index]);
    context.setFontSize(config.fontSize);
    const textWidth = measureText(labelText, config.fontSize, context);
    const textX = offsetX - 0.5 * textWidth;
    const textY = endY + 2 * opts.pix;

    context.beginPath();
    context.setFillStyle(hexToRgb(toolTipOption.labelBgColor || config.toolTipBackground, toolTipOption.labelBgOpacity || config.toolTipOpacity));
    context.setStrokeStyle(toolTipOption.labelBgColor || config.toolTipBackground);
    context.setLineWidth(1 * opts.pix);
    context.rect(textX - toolTipOption.boxPadding * opts.pix, textY, textWidth + 2 * toolTipOption.boxPadding * opts.pix, config.fontSize + 2 * toolTipOption.boxPadding * opts.pix);
    context.closePath();
    context.stroke();
    context.fill();

    context.beginPath();
    context.setFontSize(config.fontSize);
    context.setFillStyle(toolTipOption.labelFontColor || opts.fontColor);
    context.fillText(labelText, textX, textY + toolTipOption.boxPadding * opts.pix + config.fontSize);
    context.closePath();
    context.stroke();
  }
}

/**
 * 绘制标记线
 * @param opts - 图表配置选项
 * @param config - uCharts配置对象
 * @param context - Canvas 渲染上下文
 */
export function drawMarkLine(
  opts: ChartOptions,
  config: UChartsConfig,
  context: CanvasContext
): void {
  const markLineOption = assign({
    type: 'solid',
    dashLength: 4,
    data: []
  } as any, opts.extra?.markLine || {});

  const startX = opts.area![3];
  const endX = opts.width! - opts.area![1];
  const points = calMarkLineData(markLineOption.data, opts);

  for (let i = 0; i < points.length; i++) {
    const item = assign({}, {
      lineColor: '#DE4A42',
      showLabel: false,
      labelFontSize: 13,
      labelPadding: 6,
      labelFontColor: '#666666',
      labelBgColor: '#DFE8FF',
      labelBgOpacity: 0.8,
      labelAlign: 'left',
      labelOffsetX: 0,
      labelOffsetY: 0,
    }, points[i]);

    if (markLineOption.type === 'dash') {
      context.setLineDash([markLineOption.dashLength, markLineOption.dashLength]);
    }

    context.setStrokeStyle(item.lineColor);
    context.setLineWidth(1 * opts.pix);
    context.beginPath();
    context.moveTo(startX, item.y);
    context.lineTo(endX, item.y);
    context.stroke();
    context.setLineDash([]);

    if (item.showLabel) {
      const fontSize = item.labelFontSize * opts.pix;
      const labelText = item.labelText ? item.labelText : String(item.value);
      context.setFontSize(fontSize);
      const textWidth = measureText(labelText, fontSize, context);
      const bgWidth = textWidth + item.labelPadding * opts.pix * 2;
      let bgStartX = item.labelAlign === 'left' ? opts.area![3] - bgWidth : opts.width! - opts.area![1];
      bgStartX += item.labelOffsetX;
      let bgStartY = item.y - 0.5 * fontSize - item.labelPadding * opts.pix;
      bgStartY += item.labelOffsetY;
      const textX = bgStartX + item.labelPadding * opts.pix;
      const textY = item.y;

      context.setFillStyle(hexToRgb(item.labelBgColor, item.labelBgOpacity));
      context.setStrokeStyle(item.labelBgColor);
      context.setLineWidth(1 * opts.pix);
      context.beginPath();
      context.rect(bgStartX, bgStartY, bgWidth, fontSize + 2 * item.labelPadding * opts.pix);
      context.closePath();
      context.stroke();
      context.fill();

      context.setFontSize(fontSize);
      context.setTextAlign('left');
      context.setFillStyle(item.labelFontColor);
      context.fillText(labelText, textX, bgStartY + fontSize + item.labelPadding * opts.pix / 2);
      context.stroke();
      context.setTextAlign('left');
    }
  }
}

/**
 * 绘制工具提示水平线
 * @param opts - 图表配置选项
 * @param config - uCharts配置对象
 * @param context - Canvas 渲染上下文
 * @param eachSpacing - 每个数据点的间距
 * @param xAxisPoints - X轴数据点数组
 */
export function drawToolTipHorizentalLine(
  opts: ChartOptions,
  config: UChartsConfig,
  context: CanvasContext,
  eachSpacing: number,
  xAxisPoints: number[]
): void {
  const toolTipOption = assign({
    gridType: 'solid',
    dashLength: 4
  } as any, opts.extra?.tooltip || {});

  const startX = opts.area![3];
  const endX = opts.width! - opts.area![1];

  if (toolTipOption.gridType === 'dash') {
    context.setLineDash([toolTipOption.dashLength, toolTipOption.dashLength]);
  }

  context.setStrokeStyle(toolTipOption.gridColor || '#cccccc');
  context.setLineWidth(1 * opts.pix);
  context.beginPath();
  context.moveTo(startX, opts.tooltip!.offset.y);
  context.lineTo(endX, opts.tooltip!.offset.y);
  context.stroke();
  context.setLineDash([]);

  if (toolTipOption.yAxisLabel) {
    const boxPadding = toolTipOption.boxPadding * opts.pix;
    const labelText = calTooltipYAxisData(opts.tooltip!.offset.y, opts.series || [], opts, config, eachSpacing);
    const widthArr = opts.chartData?.yAxisData?.yAxisWidth || [];
    let tStartLeft = opts.area![3];
    let tStartRight = opts.width! - opts.area![1];

    for (let i = 0; i < labelText.length; i++) {
      context.setFontSize(toolTipOption.fontSize * opts.pix);
      const textWidth = measureText(labelText[i], toolTipOption.fontSize * opts.pix, context);
      let bgStartX: number, bgEndX: number, bgWidth: number;

      if (widthArr[i]?.position === 'left') {
        bgStartX = tStartLeft - (textWidth + boxPadding * 2) - 2 * opts.pix;
        bgEndX = Math.max(bgStartX, bgStartX + textWidth + boxPadding * 2);
      } else {
        bgStartX = tStartRight + 2 * opts.pix;
        bgEndX = Math.max(bgStartX + (widthArr[i]?.width || 0), bgStartX + textWidth + boxPadding * 2);
      }
      bgWidth = bgEndX - bgStartX;
      const textX = bgStartX + (bgWidth - textWidth) / 2;
      const textY = opts.tooltip!.offset.y;

      context.beginPath();
      context.setFillStyle(hexToRgb(toolTipOption.labelBgColor || config.toolTipBackground, toolTipOption.labelBgOpacity || config.toolTipOpacity));
      context.setStrokeStyle(toolTipOption.labelBgColor || config.toolTipBackground);
      context.setLineWidth(1 * opts.pix);
      context.rect(bgStartX, textY - 0.5 * config.fontSize - boxPadding, bgWidth, config.fontSize + 2 * boxPadding);
      context.closePath();
      context.stroke();
      context.fill();

      context.beginPath();
      context.setFontSize(config.fontSize);
      context.setFillStyle(toolTipOption.labelFontColor || opts.fontColor);
      context.fillText(labelText[i], textX, textY + 0.5 * config.fontSize);
      context.closePath();
      context.stroke();

      if (widthArr[i]?.position === 'left') {
        tStartLeft -= ((widthArr[i]?.width || 0) + opts.yAxis?.padding * opts.pix || 0);
      } else {
        tStartRight += (widthArr[i]?.width || 0) + opts.yAxis?.padding * opts.pix || 0;
      }
    }
  }
}

/**
 * 绘制工具提示分割区域
 * @param offsetX - X轴偏移量
 * @param opts - 图表配置选项
 * @param config - uCharts配置对象
 * @param context - Canvas 渲染上下文
 * @param eachSpacing - 每个数据点的间距
 */
export function drawToolTipSplitArea(
  offsetX: number,
  opts: ChartOptions,
  config: UChartsConfig,
  context: CanvasContext,
  eachSpacing: number
): void {
  const toolTipOption = assign({
    activeBgColor: '#000000',
    activeBgOpacity: 0.08,
    activeWidth: eachSpacing
  } as any, opts.extra?.column || {});

  toolTipOption.activeWidth = toolTipOption.activeWidth > eachSpacing ? eachSpacing : toolTipOption.activeWidth;
  const startY = opts.area![0];
  const endY = opts.height! - opts.area![2];

  context.beginPath();
  context.setFillStyle(hexToRgb(toolTipOption.activeBgColor, toolTipOption.activeBgOpacity));
  context.rect(offsetX - toolTipOption.activeWidth / 2, startY, toolTipOption.activeWidth, endY - startY);
  context.closePath();
  context.fill();
  context.setFillStyle("#FFFFFF");
}

/**
 * 绘制条形图工具提示分割区域
 * @param offsetX - X轴偏移量
 * @param opts - 图表配置选项
 * @param config - uCharts配置对象
 * @param context - Canvas 渲染上下文
 * @param eachSpacing - 每个数据点的间距
 */
export function drawBarToolTipSplitArea(
  offsetX: number,
  opts: ChartOptions,
  config: UChartsConfig,
  context: CanvasContext,
  eachSpacing: number
): void {
  const toolTipOption = assign({}, {
    activeBgColor: '#000000',
    activeBgOpacity: 0.08
  }, opts.extra?.bar);

  const startX = opts.area![3];
  const endX = opts.width! - opts.area![1];

  context.beginPath();
  context.setFillStyle(hexToRgb(toolTipOption.activeBgColor, toolTipOption.activeBgOpacity));
  context.rect(startX, offsetX - eachSpacing / 2, endX - startX, eachSpacing);
  context.closePath();
  context.fill();
  context.setFillStyle("#FFFFFF");
}

/**
 * 绘制工具提示
 * @param textList - 文本列表
 * @param offset - 偏移量
 * @param opts - 图表配置选项
 * @param config - uCharts配置对象
 * @param context - Canvas 渲染上下文
 * @param eachSpacing - 每个数据点的间距
 * @param xAxisPoints - X轴数据点数组
 */
export function drawToolTip(
  textList: ToolTipTextItem[],
  offset: Point,
  opts: ChartOptions,
  config: UChartsConfig,
  context: CanvasContext,
  eachSpacing: number,
  xAxisPoints: number[]
): void {
  const toolTipOption = assign({}, {
    showBox: true,
    showArrow: true,
    showCategory: false,
    bgColor: '#000000',
    bgOpacity: 0.7,
    borderColor: '#000000',
    borderWidth: 0,
    borderRadius: 0,
    borderOpacity: 0.7,
    boxPadding: 3,
    fontColor: '#FFFFFF',
    fontSize: 13,
    lineHeight: 20,
    legendShow: true,
    legendShape: 'auto',
    splitLine: true,
  }, opts.extra?.tooltip);

  if (toolTipOption.showCategory === true && opts.categories) {
    textList.unshift({ text: String(opts.categories[opts.tooltip!.index!]), color: null });
  }

  const fontSize = toolTipOption.fontSize * opts.pix;
  const lineHeight = toolTipOption.lineHeight * opts.pix;
  const boxPadding = toolTipOption.boxPadding * opts.pix;
  let legendWidth = fontSize;
  let legendMarginRight = 5 * opts.pix;

  if (toolTipOption.legendShow === false) {
    legendWidth = 0;
    legendMarginRight = 0;
  }

  const arrowWidth = toolTipOption.showArrow ? 8 * opts.pix : 0;
  let isOverRightBorder = false;

  if (opts.type === 'line' || opts.type === 'mount' || opts.type === 'area' || opts.type === 'candle' || opts.type === 'mix') {
    if (toolTipOption.splitLine === true) {
      drawToolTipSplitLine(opts.tooltip!.offset.x, opts, config, context);
    }
  }

  offset = assign({
    x: 0,
    y: 0
  }, offset);
  offset.y -= 8 * opts.pix;

  const textWidth = textList.map(function(item) {
    return measureText(String(item.text), fontSize, context);
  });
  const toolTipWidth = legendWidth + legendMarginRight + 4 * boxPadding + Math.max(...textWidth);
  const toolTipHeight = 2 * boxPadding + textList.length * lineHeight;

  if (toolTipOption.showBox === false) {
    return;
  }

  // 检查是否超出右边界
  if (offset.x - Math.abs(opts._scrollDistance_ || 0) + arrowWidth + toolTipWidth > opts.width!) {
    isOverRightBorder = true;
  }

  if (toolTipHeight + offset.y > opts.height!) {
    offset.y = opts.height! - toolTipHeight;
  }

  // 绘制背景矩形
  context.beginPath();
  context.setFillStyle(hexToRgb(toolTipOption.bgColor, toolTipOption.bgOpacity));
  context.setLineWidth(toolTipOption.borderWidth * opts.pix);
  context.setStrokeStyle(hexToRgb(toolTipOption.borderColor, toolTipOption.borderOpacity));
  const radius = toolTipOption.borderRadius;

  if (isOverRightBorder) {
    // 增加左侧仍然超出的判断
    if (toolTipWidth + arrowWidth > opts.width!) {
      offset.x = opts.width! + Math.abs(opts._scrollDistance_ || 0) + arrowWidth + (toolTipWidth - opts.width!);
    }
    if (toolTipWidth > offset.x) {
      offset.x = opts.width! + Math.abs(opts._scrollDistance_ || 0) + arrowWidth + (toolTipWidth - opts.width!);
    }
    if (toolTipOption.showArrow) {
      context.moveTo(offset.x, offset.y + 10 * opts.pix);
      context.lineTo(offset.x - arrowWidth, offset.y + 10 * opts.pix + 5 * opts.pix);
    }
    context.arc(offset.x - arrowWidth - radius, offset.y + toolTipHeight - radius, radius, 0, Math.PI / 2, false);
    context.arc(offset.x - arrowWidth - Math.round(toolTipWidth) + radius, offset.y + toolTipHeight - radius, radius, Math.PI / 2, Math.PI, false);
    context.arc(offset.x - arrowWidth - Math.round(toolTipWidth) + radius, offset.y + radius, radius, -Math.PI, -Math.PI / 2, false);
    context.arc(offset.x - arrowWidth - radius, offset.y + radius, radius, -Math.PI / 2, 0, false);
    if (toolTipOption.showArrow) {
      context.lineTo(offset.x - arrowWidth, offset.y + 10 * opts.pix - 5 * opts.pix);
      context.lineTo(offset.x, offset.y + 10 * opts.pix);
    }
  } else {
    if (toolTipOption.showArrow) {
      context.moveTo(offset.x, offset.y + 10 * opts.pix);
      context.lineTo(offset.x + arrowWidth, offset.y + 10 * opts.pix - 5 * opts.pix);
    }
    context.arc(offset.x + arrowWidth + radius, offset.y + radius, radius, -Math.PI, -Math.PI / 2, false);
    context.arc(offset.x + arrowWidth + Math.round(toolTipWidth) - radius, offset.y + radius, radius, -Math.PI / 2, 0, false);
    context.arc(offset.x + arrowWidth + Math.round(toolTipWidth) - radius, offset.y + toolTipHeight - radius, radius, 0, Math.PI / 2, false);
    context.arc(offset.x + arrowWidth + radius, offset.y + toolTipHeight - radius, radius, Math.PI / 2, Math.PI, false);
    if (toolTipOption.showArrow) {
      context.lineTo(offset.x + arrowWidth, offset.y + 10 * opts.pix + 5 * opts.pix);
      context.lineTo(offset.x, offset.y + 10 * opts.pix);
    }
  }
  context.closePath();
  context.fill();

  if (toolTipOption.borderWidth > 0) {
    context.stroke();
  }

  // 绘制图例
  if (toolTipOption.legendShow) {
    textList.forEach(function(item) {
      if (item.color !== null) {
        context.beginPath();
        context.setFillStyle(item.color);
        let startX = offset.x + arrowWidth + 2 * boxPadding;
        const startY = offset.y + (lineHeight - fontSize) / 2 + lineHeight * textList.indexOf(item) + boxPadding + 1;

        if (isOverRightBorder) {
          startX = offset.x - toolTipWidth - arrowWidth + 2 * boxPadding;
        }

        switch (item.legendShape) {
          case 'line':
            context.moveTo(startX, startY + 0.5 * legendWidth - 2 * opts.pix);
            context.fillRect(startX, startY + 0.5 * legendWidth - 2 * opts.pix, legendWidth, 4 * opts.pix);
            break;
          case 'triangle':
            context.moveTo(startX + 7.5 * opts.pix, startY + 0.5 * legendWidth - 5 * opts.pix);
            context.lineTo(startX + 2.5 * opts.pix, startY + 0.5 * legendWidth + 5 * opts.pix);
            context.lineTo(startX + 12.5 * opts.pix, startY + 0.5 * legendWidth + 5 * opts.pix);
            context.lineTo(startX + 7.5 * opts.pix, startY + 0.5 * legendWidth - 5 * opts.pix);
            break;
          case 'diamond':
            context.moveTo(startX + 7.5 * opts.pix, startY + 0.5 * legendWidth - 5 * opts.pix);
            context.lineTo(startX + 2.5 * opts.pix, startY + 0.5 * legendWidth);
            context.lineTo(startX + 7.5 * opts.pix, startY + 0.5 * legendWidth + 5 * opts.pix);
            context.lineTo(startX + 12.5 * opts.pix, startY + 0.5 * legendWidth);
            context.lineTo(startX + 7.5 * opts.pix, startY + 0.5 * legendWidth - 5 * opts.pix);
            break;
          case 'circle':
            context.moveTo(startX + 7.5 * opts.pix, startY + 0.5 * legendWidth);
            context.arc(startX + 7.5 * opts.pix, startY + 0.5 * legendWidth, 5 * opts.pix, 0, 2 * Math.PI);
            break;
          case 'rect':
            context.moveTo(startX, startY + 0.5 * legendWidth - 5 * opts.pix);
            context.fillRect(startX, startY + 0.5 * legendWidth - 5 * opts.pix, 15 * opts.pix, 10 * opts.pix);
            break;
          case 'square':
            context.moveTo(startX + 2 * opts.pix, startY + 0.5 * legendWidth - 5 * opts.pix);
            context.fillRect(startX + 2 * opts.pix, startY + 0.5 * legendWidth - 5 * opts.pix, 10 * opts.pix, 10 * opts.pix);
            break;
          default:
            context.moveTo(startX, startY + 0.5 * legendWidth - 5 * opts.pix);
            context.fillRect(startX, startY + 0.5 * legendWidth - 5 * opts.pix, 15 * opts.pix, 10 * opts.pix);
        }
        context.closePath();
        context.fill();
      }
    });
  }

  // 绘制文本列表
  textList.forEach(function(item) {
    let startX = offset.x + arrowWidth + 2 * boxPadding + legendWidth + legendMarginRight;
    if (isOverRightBorder) {
      startX = offset.x - toolTipWidth - arrowWidth + 2 * boxPadding + legendWidth + legendMarginRight;
    }
    const startY = offset.y + lineHeight * textList.indexOf(item) + (lineHeight - fontSize) / 2 - 1 + boxPadding + fontSize;

    context.beginPath();
    context.setFontSize(fontSize);
    context.setTextBaseline('normal');
    context.setFillStyle(toolTipOption.fontColor);
    context.fillText(String(item.text), startX, startY);
    context.closePath();
    context.stroke();
  });
}

/**
 * 绘制工具提示桥接函数
 * @param opts - 图表配置选项
 * @param config - uCharts配置对象
 * @param context - Canvas 渲染上下文
 * @param process - 动画进程 (0-1)
 * @param eachSpacing - 每个数据点的间距
 * @param xAxisPoints - X轴数据点数组
 */
export function drawToolTipBridge(
  opts: ChartOptions,
  config: UChartsConfig,
  context: CanvasContext,
  process: number,
  eachSpacing: number,
  xAxisPoints: number[]
): void {
  const toolTipOption = opts.extra?.tooltip || {};
  if (toolTipOption.horizentalLine && opts.tooltip && process === 1 && (opts.type === 'line' || opts.type === 'area' || opts.type === 'column' || opts.type === 'mount' || opts.type === 'candle' || opts.type === 'mix')) {
    drawToolTipHorizentalLine(opts, config, context, eachSpacing, xAxisPoints);
  }
  context.save();
  if (opts._scrollDistance_ && opts._scrollDistance_ !== 0 && opts.enableScroll === true) {
    context.translate(opts._scrollDistance_, 0);
  }
  if (opts.tooltip && opts.tooltip.textList && opts.tooltip.textList.length && process === 1) {
    drawToolTip(opts.tooltip.textList, opts.tooltip.offset, opts, config, context, eachSpacing, xAxisPoints);
  }
  context.restore();
}

/**
 * 绘制Canvas
 * @param opts - 图表配置选项
 * @param context - Canvas 渲染上下文
 */
export function drawCanvas(opts: ChartOptions, context: CanvasContext): void {
  context.save();
  context.translate(0, 0.5);
  context.restore();
  context.draw();
}
