/**
 * 其他辅助函数模块
 * 包含轴文本列表、tooltip数据、标记线数据、上下文旋转、随机数、碰撞检测和词云点计算等辅助函数
 */

// @ts-nocheck - 为了与原始 u-charts 代码保持兼容性，跳过类型检查

import type { ChartOptions, SeriesItem } from '../data-processing/index';
import { measureText } from '../utils/text';
import { dataCombine, dataCombineStack, getDataRange } from '../data-processing/index';

// 使用 any 类型来简化与原始 u-charts 代码的兼容性
type AnyChartOptions = any;

/**
 * 获取X轴文本列表
 * @param series 数据系列
 * @param opts 图表配置选项
 * @param config 图表配置
 * @param stack 是否堆叠
 * @param index Y轴索引
 * @returns 文本列表
 */
export function getXAxisTextList(
  series: SeriesItem[],
  opts: AnyChartOptions,
  config: any,
  stack: string,
  index: number = -1
): number[] {
  let data: any[];
  if (stack === 'stack') {
    data = dataCombineStack(series, opts.categories.length);
  } else {
    data = dataCombine(series);
  }

  const sorted: any[] = [];
  // remove null from data
  const filteredData = data.filter(function (item) {
    if (typeof item === 'object' && item !== null) {
      if (Array.isArray(item)) {
        return item !== null;
      } else {
        return item.value !== null;
      }
    } else {
      return item !== null;
    }
  });

  filteredData.forEach(function (item) {
    if (typeof item === 'object') {
      if (Array.isArray(item)) {
        if (opts.type === 'candle') {
          item.forEach(function (subitem: any) {
            sorted.push(subitem);
          });
        } else {
          sorted.push(item[0]);
        }
      } else {
        sorted.push(item.value);
      }
    } else {
      sorted.push(item);
    }
  });

  let minData = 0;
  let maxData = 0;
  if (sorted.length > 0) {
    minData = Math.min.apply(null, sorted);
    maxData = Math.max.apply(null, sorted);
  }

  // 为了兼容v1.9.0之前的项目
  if (index > -1) {
    if (typeof opts.xAxis.data[index].min === 'number') {
      minData = Math.min(opts.xAxis.data[index].min, minData);
    }
    if (typeof opts.xAxis.data[index].max === 'number') {
      maxData = Math.max(opts.xAxis.data[index].max, maxData);
    }
  } else {
    if (typeof opts.xAxis.min === 'number') {
      minData = Math.min(opts.xAxis.min, minData);
    }
    if (typeof opts.xAxis.max === 'number') {
      maxData = Math.max(opts.xAxis.max, maxData);
    }
  }

  if (minData === maxData) {
    const rangeSpan = maxData || 10;
    maxData += rangeSpan;
  }

  const minRange = minData;
  const maxRange = maxData;
  const range: number[] = [];
  const eachRange = (maxRange - minRange) / opts.xAxis.splitNumber;
  for (let i = 0; i <= opts.xAxis.splitNumber; i++) {
    range.push(minRange + eachRange * i);
  }
  return range;
}

/**
 * 获取Y轴文本列表
 * @param series 数据系列
 * @param opts 图表配置选项
 * @param config 图表配置
 * @param stack 是否堆叠
 * @param yData Y轴数据
 * @param index Y轴索引
 * @returns 文本列表
 */
export function getYAxisTextList(
  series: SeriesItem[],
  opts: AnyChartOptions,
  config: any,
  stack: string,
  yData: { min?: number; max?: number },
  index: number = -1
): number[] {
  let data: any[];
  if (stack === 'stack') {
    data = dataCombineStack(series, opts.categories.length);
  } else {
    data = dataCombine(series);
  }

  const sorted: any[] = [];
  // remove null from data
  const filteredData = data.filter(function (item) {
    if (typeof item === 'object' && item !== null) {
      if (Array.isArray(item)) {
        return item !== null;
      } else {
        return item.value !== null;
      }
    } else {
      return item !== null;
    }
  });

  filteredData.forEach(function (item) {
    if (typeof item === 'object') {
      if (Array.isArray(item)) {
        if (opts.type === 'candle') {
          item.forEach(function (subitem: any) {
            sorted.push(subitem);
          });
        } else {
          sorted.push(item[1]);
        }
      } else {
        sorted.push(item.value);
      }
    } else {
      sorted.push(item);
    }
  });

  let minData = yData.min || 0;
  let maxData = yData.max || 0;
  if (sorted.length > 0) {
    minData = Math.min.apply(null, sorted);
    maxData = Math.max.apply(null, sorted);
  }

  if (minData === maxData) {
    if (maxData === 0) {
      maxData = 10;
    } else {
      minData = 0;
    }
  }

  const dataRange = getDataRange(minData, maxData);
  const minRange =
    yData.min === undefined || yData.min === null
      ? dataRange.minRange
      : yData.min;
  const maxRange =
    yData.max === undefined || yData.max === null
      ? dataRange.maxRange
      : yData.max;
  const eachRange = (maxRange - minRange) / opts.yAxis.splitNumber;
  const range: number[] = [];
  for (let i = 0; i <= opts.yAxis.splitNumber; i++) {
    range.push(minRange + eachRange * i);
  }
  return range.reverse();
}

/**
 * 计算提示框Y轴数据
 * @param point 当前触摸点坐标
 * @param series 数据系列
 * @param opts 图表配置选项
 * @param config 图表配置
 * @param eachSpacing 每个数据点的间距
 * @returns Y轴数据数组
 */
export function calTooltipYAxisData(
  point: { x: number; y: number },
  series: SeriesItem[],
  opts: AnyChartOptions,
  config: any,
  eachSpacing: number
): string[] {
  const ranges: number[][] = [].concat(opts.chartData.yAxisData.ranges);
  const spacingValid = opts.height - opts.area[0] - opts.area[2];
  const minAxis = opts.area[0];
  const items: string[] = [];

  for (let i = 0; i < ranges.length; i++) {
    const maxVal = Math.max.apply(null, ranges[i]);
    const minVal = Math.min.apply(null, ranges[i]);
    let item = maxVal - ((maxVal - minVal) * (point.y - minAxis)) / spacingValid;
    item =
      opts.yAxis.data && opts.yAxis.data[i].formatter
        ? opts.yAxis.data[i].formatter(item, i, opts)
        : item.toFixed(0);
    items.push(String(item));
  }
  return items;
}

/**
 * 计算标记线数据
 * @param points 标记线点数组
 * @param opts 图表配置选项
 * @returns 标记线数据数组
 */
export function calMarkLineData(
  points: Array<{ value: number; yAxisIndex?: number; y?: number }>,
  opts: AnyChartOptions
): Array<{ value: number; yAxisIndex?: number; y?: number }> {
  let minRange: number, maxRange: number;
  const spacingValid = opts.height - opts.area[0] - opts.area[2];

  for (let i = 0; i < points.length; i++) {
    points[i].yAxisIndex = points[i].yAxisIndex ? points[i].yAxisIndex : 0;
    const range = [].concat(opts.chartData.yAxisData.ranges[points[i].yAxisIndex!]);
    minRange = range.pop() as number;
    maxRange = range.shift() as number;
    const height =
      (spacingValid * (points[i].value - minRange)) / (maxRange - minRange);
    points[i].y = opts.height - Math.round(height) - opts.area[2];
  }
  return points;
}

/**
 * 上下文旋转
 * @param context Canvas上下文
 * @param opts 图表配置选项
 */
export function contextRotate(
  context: any,
  opts: AnyChartOptions
): void {
  if (opts.rotateLock !== true) {
    context.translate(opts.height, 0);
    context.rotate((90 * Math.PI) / 180);
  } else if (opts._rotate_ !== true) {
    context.translate(opts.height, 0);
    context.rotate((90 * Math.PI) / 180);
    opts._rotate_ = true;
  }
}

/**
 * 生成标准化整数随机数
 * @param min 最小值
 * @param max 最大值
 * @param iter 迭代次数
 * @returns 随机整数
 */
export function normalInt(min: number, max: number, iter: number): number {
  iter = iter === 0 ? 1 : iter;
  const arr: number[] = [];
  for (let i = 0; i < iter; i++) {
    arr[i] = Math.random();
  }
  return (
    Math.floor((arr.reduce((i, j) => i + j) / iter) * (max - min)) + min
  );
}

/**
 * 新碰撞检测
 * @param area 区域 [x1, y1, x2, y2]
 * @param points 点数组
 * @param width 宽度
 * @param height 高度
 * @returns 是否碰撞
 */
export function collisionNew(
  area: number[],
  points: Array<{ area?: number[] }>,
  width: number,
  height: number
): boolean {
  let isIn = false;
  for (let i = 0; i < points.length; i++) {
    if (points[i].area) {
      if (
        area[3] < points[i].area![1] ||
        area[0] > points[i].area![2] ||
        area[1] > points[i].area![3] ||
        area[2] < points[i].area![0]
      ) {
        if (
          area[0] < 0 ||
          area[1] < 0 ||
          area[2] > width ||
          area[3] > height
        ) {
          isIn = true;
          break;
        } else {
          isIn = false;
        }
      } else {
        isIn = true;
        break;
      }
    }
  }
  return isIn;
}

/**
 * 获取词云点
 * @param opts 图表配置选项
 * @param type 类型 ('normal' | 'vertical')
 * @param context Canvas上下文
 * @returns 词云数据点数组
 */
export function getWordCloudPoint(
  opts: AnyChartOptions,
  type: 'normal' | 'vertical',
  context: any
): Array<{
  name: string;
  textSize: number;
  area: number[];
  areav?: number[];
  rotate?: boolean;
}> {
  const points = opts.series;

  switch (type) {
    case 'normal':
      for (let i = 0; i < points.length; i++) {
        const text = points[i].name;
        const tHeight = points[i].textSize * opts.pix;
        const tWidth = measureText(text, tHeight, context);
        let x: number, y: number;
        let area: number[];
        let breaknum = 0;
        while (true) {
          breaknum++;
          x = normalInt(-opts.width / 2, opts.width / 2, 5) - tWidth / 2;
          y = normalInt(-opts.height / 2, opts.height / 2, 5) + tHeight / 2;
          area = [
            x - 5 + opts.width / 2,
            y - 5 - tHeight + opts.height / 2,
            x + tWidth + 5 + opts.width / 2,
            y + 5 + opts.height / 2,
          ];
          const isCollision = collisionNew(area, points, opts.width, opts.height);
          if (!isCollision) break;
          if (breaknum === 1000) {
            area = [-100, -100, -100, -100];
            break;
          }
        }
        (points[i] as any).area = area;
      }
      break;

    case 'vertical':
      function Spin(): boolean {
        // 获取均匀随机值，是否旋转，旋转的概率为（1-0.5）
        if (Math.random() > 0.7) {
          return true;
        } else {
          return false;
        }
      }
      for (let i = 0; i < points.length; i++) {
        const text = points[i].name;
        const tHeight = points[i].textSize * opts.pix;
        const tWidth = measureText(text, tHeight, context);
        const isSpin = Spin();
        let x: number, y: number, area: number[], areav: number[] | undefined;
        let breaknum = 0;
        while (true) {
          breaknum++;
          let isCollision: boolean;
          if (isSpin) {
            x = normalInt(-opts.width / 2, opts.width / 2, 5) - tWidth / 2;
            y = normalInt(-opts.height / 2, opts.height / 2, 5) + tHeight / 2;
            area = [
              y - 5 - tWidth + opts.width / 2,
              -x - 5 + opts.height / 2,
              y + 5 + opts.width / 2,
              -x + tHeight + 5 + opts.height / 2,
            ];
            areav = [
              opts.width -
                (opts.width / 2 - opts.height / 2) -
                (-x + tHeight + 5 + opts.height / 2) -
                5,
              (opts.height / 2 - opts.width / 2) +
                (y - 5 - tWidth + opts.width / 2) -
                5,
              opts.width -
                (opts.width / 2 - opts.height / 2) -
                (-x + tHeight + 5 + opts.height / 2) +
                tHeight,
              (opts.height / 2 - opts.width / 2) +
                (y - 5 - tWidth + opts.width / 2) +
                tWidth +
                5,
            ];
            isCollision = collisionNew(areav, points, opts.height, opts.width);
          } else {
            x = normalInt(-opts.width / 2, opts.width / 2, 5) - tWidth / 2;
            y = normalInt(-opts.height / 2, opts.height / 2, 5) + tHeight / 2;
            area = [
              x - 5 + opts.width / 2,
              y - 5 - tHeight + opts.height / 2,
              x + tWidth + 5 + opts.width / 2,
              y + 5 + opts.height / 2,
            ];
            isCollision = collisionNew(area, points, opts.width, opts.height);
          }
          if (!isCollision) break;
          if (breaknum === 1000) {
            area = [-1000, -1000, -1000, -1000];
            break;
          }
        }
        if (isSpin) {
          (points[i] as any).area = areav;
          (points[i] as any).areav = area;
        } else {
          (points[i] as any).area = area;
        }
        (points[i] as any).rotate = isSpin;
      }
      break;
  }

  return points as any;
}
