import { each, pick } from '@antv/util';
import { BBox, IGroup, IShape } from '../../../dependents';
import { getCoordinateBBox } from '../../../util/coordinate';
import { getEllipsisText } from '../../../util/text';
import { translate } from '../../../util/transform';
import { LabelItem } from '../interface';

/** limitInPlot layout 的可选配置 */
export interface LimitInPlotLayoutCfg {
  /** 需要限制哪些方向上不能超过 Plot 范围，默认四个方向上都限制 */
  direction?: ('top' | 'right' | 'bottom' | 'left')[];
  /** 可以允许的 margin */
  margin?: number;
  /** 超过限制后的动作，默认 translate 移动位置; ellipsis 对 text 进行省略展示 */
  action?: 'hide' | 'translate' | 'ellipsis';
}

/**
 * @ignore
 * 将 label 限制在 Plot 范围内，将超出 Plot 范围的 label 可选择进行隐藏或者移动位置
 * @param labels
 * @param cfg
 */
export function limitInPlot(
  items: LabelItem[],
  labels: IGroup[],
  shapes: IShape[] | IGroup[],
  region: BBox,
  cfg?: LimitInPlotLayoutCfg
) {
  if (labels.length <= 0) {
    return;
  }
  const direction = cfg?.direction || ['top', 'right', 'bottom', 'left'];
  const action = cfg?.action || 'translate';
  const margin = cfg?.margin || 0;
  const coordinate = labels[0].get('coordinate');
  if (!coordinate) {
    return;
  }
  const { minX: regionMinX, minY: regionMinY, maxX: regionMaxX, maxY: regionMaxY } = getCoordinateBBox(
    coordinate,
    margin
  );

  each(labels, (label: IGroup) => {
    const { minX, minY, maxX, maxY, x, y, width, height } = label.getCanvasBBox();

    let finalX = x;
    let finalY = y;
    if (direction.indexOf('left') >= 0 && (minX < regionMinX || maxX < regionMinX)) {
      // 超出左侧
      finalX = regionMinX;
    }
    if (direction.indexOf('top') >= 0 && (minY < regionMinY || maxY < regionMinY)) {
      // 超出顶部
      finalY = regionMinY;
    }

    if (direction.indexOf('right') >= 0) {
      if (minX > regionMaxX) {
        // 整体超出右侧
        finalX = regionMaxX - width;
      } else if (maxX > regionMaxX) {
        // 超出右侧
        finalX = finalX - (maxX - regionMaxX);
      }
    }

    if (direction.indexOf('bottom') >= 0) {
      if (minY > regionMaxY) {
        // 整体超出底部
        finalY = regionMaxY - height;
      } else if (maxY > regionMaxY) {
        // 超出底部
        finalY = finalY - (maxY - regionMaxY);
      }
    }

    if (finalX !== x || finalY !== y) {
      const translateX = finalX - x;
      if (action === 'translate') {
        translate(label, translateX, finalY - y);
      } else if (action === 'ellipsis') {
        const textShapes = label.findAll((shape) => shape.get('type') === 'text');
        textShapes.forEach((textShape) => {
          const style = pick(textShape.attr(), ['fontSize', 'fontFamily', 'fontWeight', 'fontStyle', 'fontVariant']);
          const textBox = textShape.getCanvasBBox();
          const text = getEllipsisText(textShape.attr('text'), textBox.width - Math.abs(translateX), style);
          textShape.attr('text', text);
        });
      } else {
        label.hide();
      }
    }
  });
}
