/**
 * 雷达图绘制函数
 *
 * 从 u-charts 核心库搬迁的雷达图绘制相关函数
 */
// @ts-nocheck - 由于从 u-charts 搬迁，类型系统不兼容，暂时禁用类型检查

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

export type CanvasContext = any;

export interface Point {
  x: number;
  y: number;
}

export interface RadarOption {
  gridColor: string;
  gridType: string;
  gridEval: number;
  axisLabel: boolean;
  axisLabelTofix: number;
  labelShow: boolean;
  labelColor: string;
  labelPointShow: boolean;
  labelPointRadius: number;
  labelPointColor: string;
  opacity: number;
  gridCount: number;
  border: boolean;
  borderWidth: number;
  linearType: string;
  customColor: string[];
  max?: number;
  radius?: number;
}

function getRadarCoordinateSeries(length: number): number[] {
  let eachAngle = 2 * Math.PI / length;
  let CoordinateSeries: number[] = [];
  for (let i = 0; i < length; i++) {
    CoordinateSeries.push(eachAngle * i);
  }
  return CoordinateSeries.map(function(item) {
    return -1 * item + Math.PI / 2;
  });
}

function getMaxTextListLength(list: string[], fontSize: number, context: CanvasContext): number {
  let lengthList = list.map(function(item) {
    return measureText(item, fontSize, context);
  });
  return Math.max.apply(null, lengthList);
}

function fillCustomColor(linearType: string, customColor: string[], series: SeriesItem[], config: UChartsConfig): string[] {
  let newcolor = customColor || [];
  if (linearType == 'custom' && newcolor.length == 0) {
    newcolor = config.linearColor;
  }
  if (linearType == 'custom' && newcolor.length < series.length) {
    let chazhi = series.length - newcolor.length;
    for (let i = 0; i < chazhi; i++) {
      newcolor.push(config.linearColor[(i + 1) % config.linearColor.length]);
    }
  }
  return newcolor;
}

function dataCombine(series: SeriesItem[]): number[] {
  return series.reduce(function(a: number[], b) {
    return (a.data ? a.data : a).concat(b.data as number[]);
  }, [] as number[]);
}

function drawPointShape(points: Point[], color: string, shape: string, context: CanvasContext, opts: ChartOptions): void {
  context.beginPath();
  context.setStrokeStyle(color);
  context.setFillStyle(color);
  context.setLineWidth(1 * opts.pix);
  if (shape === 'diamond') {
    points.forEach(function(item, index) {
      if (item !== null) {
        context.moveTo(item.x, item.y - 3.5);
        context.lineTo(item.x - 3.5, item.y);
        context.lineTo(item.x, item.y + 3.5);
        context.lineTo(item.x + 3.5, item.y);
        context.lineTo(item.x, item.y - 3.5);
      }
    });
  } else if (shape === 'circle') {
    points.forEach(function(item, index) {
      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, index) {
      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, index) {
      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 {
    points.forEach(function(item, index) {
      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);
      }
    });
  }
  context.closePath();
  context.fill();
  context.stroke();
}

export function drawRadarDataPoints(
  series: SeriesItem[],
  opts: ChartOptions,
  config: UChartsConfig,
  context: CanvasContext
): { center: Point; radius: number; angleList: number[] } {
  let radarOption = assign({}, {
    gridColor: '#cccccc',
    gridType: 'radar',
    gridEval: 1,
    axisLabel: false,
    axisLabelTofix: 0,
    labelShow: true,
    labelColor: '#666666',
    labelPointShow: false,
    labelPointRadius: 3,
    labelPointColor: '#cccccc',
    opacity: 0.2,
    gridCount: 3,
    border: false,
    borderWidth: 2,
    linearType: 'none',
    customColor: [],
  }, opts.extra.radar) as RadarOption;

  let coordinateAngle = getRadarCoordinateSeries(opts.categories!.length);
  let centerPosition = {
    x: opts.area[3] + (opts.width - opts.area[1] - opts.area[3]) / 2,
    y: opts.area[0] + (opts.height - opts.area[0] - opts.area[2]) / 2
  };

  let xr = (opts.width - opts.area[1] - opts.area[3]) / 2;
  let yr = (opts.height - opts.area[0] - opts.area[2]) / 2;
  let radius = Math.min(xr - (getMaxTextListLength(opts.categories!, config.fontSize, context) + config.radarLabelTextMargin), yr - config.radarLabelTextMargin);
  radius -= config.radarLabelTextMargin * opts.pix;
  radius = radius < 10 ? 10 : radius;
  radius = radarOption.radius ? radarOption.radius : radius;

  // 画分割线
  context.beginPath();
  context.setLineWidth(1 * opts.pix);
  context.setStrokeStyle(radarOption.gridColor);
  coordinateAngle.forEach(function(angle, index) {
    let pos = convertCoordinateOrigin(radius * Math.cos(angle), radius * Math.sin(angle), centerPosition);
    context.moveTo(centerPosition.x, centerPosition.y);
    if (index % radarOption.gridEval == 0) {
      context.lineTo(pos.x, pos.y);
    }
  });
  context.stroke();
  context.closePath();

  // 画背景网格
  for (let i = 1; i <= radarOption.gridCount; i++) {
    let startPos = {};
    context.beginPath();
    context.setLineWidth(1 * opts.pix);
    context.setStrokeStyle(radarOption.gridColor);
    if (radarOption.gridType == 'radar') {
      coordinateAngle.forEach(function(angle, index) {
        let pos = convertCoordinateOrigin(radius / radarOption.gridCount * i * Math.cos(angle), radius /
          radarOption.gridCount * i * Math.sin(angle), centerPosition);
        if (index === 0) {
          startPos = pos;
          context.moveTo(pos.x, pos.y);
        } else {
          context.lineTo(pos.x, pos.y);
        }
      });
      context.lineTo((startPos as Point).x, (startPos as Point).y);
    } else {
      let pos = convertCoordinateOrigin(radius / radarOption.gridCount * i * Math.cos(1.5), radius / radarOption.gridCount * i * Math.sin(1.5), centerPosition);
      context.arc(centerPosition.x, centerPosition.y, centerPosition.y - pos.y, 0, 2 * Math.PI, false);
    }
    context.stroke();
    context.closePath();
  }

  radarOption.customColor = fillCustomColor(radarOption.linearType, radarOption.customColor, series, config);
  let radarDataPoints = getRadarDataPoints(coordinateAngle, centerPosition, radius, series as any, opts);

  radarDataPoints.forEach(function(eachSeries, seriesIndex) {
    // 绘制区域数据
    context.beginPath();
    context.setLineWidth(radarOption.borderWidth * opts.pix);
    context.setStrokeStyle(eachSeries.color!);

    let fillcolor = hexToRgb(eachSeries.color!, radarOption.opacity);
    if (radarOption.linearType == 'custom') {
      let grd;
      if (context.createCircularGradient) {
        grd = context.createCircularGradient(centerPosition.x, centerPosition.y, radius);
      } else {
        grd = context.createRadialGradient(centerPosition.x, centerPosition.y, 0, centerPosition.x, centerPosition.y, radius);
      }
      grd.addColorStop(0, hexToRgb(radarOption.customColor[series[seriesIndex].linearIndex!], radarOption.opacity));
      grd.addColorStop(1, hexToRgb(eachSeries.color!, radarOption.opacity));
      fillcolor = grd;
    }

    context.setFillStyle(fillcolor);
    eachSeries.data.forEach(function(item: any, index: number) {
      if (index === 0) {
        context.moveTo(item.position.x, item.position.y);
      } else {
        context.lineTo(item.position.x, item.position.y);
      }
    });
    context.closePath();
    context.fill();
    if (radarOption.border === true) {
      context.stroke();
    }
    context.closePath();

    if (opts.dataPointShape !== false) {
      let points = eachSeries.data.map(function(item: any) {
        return item.position;
      });
      drawPointShape(points, eachSeries.color!, eachSeries.pointShape!, context, opts);
    }
  });

  // 画刻度值
  if (radarOption.axisLabel === true) {
    const maxData = Math.max(radarOption.max || 0, Math.max.apply(null, dataCombine(series)));
    const stepLength = radius / radarOption.gridCount;
    const fontSize = opts.fontSize! * opts.pix;
    context.setFontSize(fontSize);
    context.setFillStyle(opts.fontColor!);
    context.setTextAlign('left');
    for (let i = 0; i < radarOption.gridCount + 1; i++) {
      let label = i * maxData / radarOption.gridCount;
      label = Number(label.toFixed(radarOption.axisLabelTofix));
      context.fillText(String(label), centerPosition.x + 3 * opts.pix, centerPosition.y - i * stepLength + fontSize / 2);
    }
  }

  // draw label text
  drawRadarLabel(coordinateAngle, radius, centerPosition, opts, config, context);

  // draw dataLabel
  if (opts.dataLabel !== false && process === 1) {
    radarDataPoints.forEach(function(eachSeries: any, seriesIndex: number) {
      context.beginPath();
      let fontSize = eachSeries.textSize * opts.pix || config.fontSize;
      context.setFontSize(fontSize);
      context.setFillStyle(eachSeries.textColor || opts.fontColor);
      eachSeries.data.forEach(function(item: any, index: number) {
        // 如果是中心点垂直的上下点位
        if (Math.abs(item.position.x - centerPosition.x) < 2) {
          // 如果在上面
          if (item.position.y < centerPosition.y) {
            context.setTextAlign('center');
            context.fillText(item.value, item.position.x, item.position.y - 4);
          } else {
            context.setTextAlign('center');
            context.fillText(item.value, item.position.x, item.position.y + fontSize + 2);
          }
        } else {
          // 如果在左侧
          if (item.position.x < centerPosition.x) {
            context.setTextAlign('right');
            context.fillText(item.value, item.position.x - 4, item.position.y + fontSize / 2 - 2);
          } else {
            context.setTextAlign('left');
            context.fillText(item.value, item.position.x + 4, item.position.y + fontSize / 2 - 2);
          }
        }
      });
      context.closePath();
      context.stroke();
    });
    context.setTextAlign('left');
  }

  return {
    center: centerPosition,
    radius: radius,
    angleList: coordinateAngle
  };
}

export function drawRadarLabel(
  angleList: number[],
  radius: number,
  centerPosition: Point,
  opts: ChartOptions,
  config: UChartsConfig,
  context: CanvasContext
): void {
  let radarOption = opts.extra.radar || {};
  angleList.forEach(function(angle, index) {
    if (radarOption.labelPointShow === true && opts.categories![index] !== '') {
      let posPoint = {
        x: radius * Math.cos(angle),
        y: radius * Math.sin(angle)
      };
      let posPointAxis = convertCoordinateOrigin(posPoint.x, posPoint.y, centerPosition);
      context.setFillStyle(radarOption.labelPointColor);
      context.beginPath();
      context.arc(posPointAxis.x, posPointAxis.y, radarOption.labelPointRadius * opts.pix, 0, 2 * Math.PI, false);
      context.closePath();
      context.fill();
    }
    if (radarOption.labelShow === true) {
      let pos = {
        x: (radius + config.radarLabelTextMargin * opts.pix) * Math.cos(angle),
        y: (radius + config.radarLabelTextMargin * opts.pix) * Math.sin(angle)
      };
      let posRelativeCanvas = convertCoordinateOrigin(pos.x, pos.y, centerPosition);
      let startX = posRelativeCanvas.x;
      let startY = posRelativeCanvas.y;
      if (Math.abs(pos.x) < 1e-10) {
        startX -= measureText(opts.categories![index] || '', config.fontSize, context) / 2;
      } else if (pos.x < 0) {
        startX -= measureText(opts.categories![index] || '', config.fontSize, context);
      }
      context.beginPath();
      context.setFontSize(config.fontSize);
      context.setFillStyle(radarOption.labelColor || opts.fontColor);
      context.fillText(opts.categories![index] || '', startX, startY + config.fontSize / 2);
      context.closePath();
      context.stroke();
    }
  });
}
