import { IGroup, View } from '@antv/g2';
import { each, get, isFunction, isNumber, isString } from '@antv/util';
import { Datum, ShapeStyle, Statistic, StatisticText } from '../types';
import { kebabCase } from './kebab-case';
import { pick } from './pick';

/**
 * @desc 生成 html-statistic 的 style 字符串 (兼容 canvas 的 shapeStyle 到 css样式上)
 *
 * @param width
 * @param style
 */
export function adapteStyle(style?: StatisticText['style']): object {
  const styleObject = {
    overflow: 'hidden',
    'white-space': 'nowrap',
    'text-overflow': 'ellipsis',
    display: 'flex',
    justifyContent: 'center',
    alignItems: 'center',
  };

  const shapeStyleKeys = [
    'stroke',
    'lineWidth',
    'shadowColor',
    'strokeOpacity',
    'shadowBlur',
    'shadowOffsetX',
    'shadowOffsetY',
    'fill',
  ];

  // 兼容 shapeStyle 设置 · start
  if (get(style, 'fill')) {
    styleObject['color'] = style['fill'];
  }
  const {
    shadowColor,
    shadowBlur = 0,
    shadowOffsetX = 0,
    shadowOffsetY = 0,
  } = pick(style, shapeStyleKeys) as ShapeStyle;
  styleObject['text-shadow'] = `${[shadowColor, `${shadowOffsetX}px`, `${shadowOffsetY}px`, `${shadowBlur}px`].join(
    ' '
  )}`;

  const { stroke, lineWidth = 0 } = pick(style, shapeStyleKeys) as ShapeStyle;
  styleObject['-webkit-text-stroke'] = `${[`${lineWidth}px`, stroke].join(' ')}`;
  // 兼容 shapeStyle 设置 · end

  each(style, (v, k) => {
    //  兼容 shapeStyle 的 fontSize 没有单位
    if (['fontSize'].includes(k) && isNumber(v)) {
      styleObject[kebabCase(k)] = `${v}px`;
    } else if (k && !shapeStyleKeys.includes(k)) {
      styleObject[kebabCase(k)] = `${v}`;
    }
  });

  return styleObject;
}

/**
 * @desc 设置 html-statistic 容器的默认样式
 *
 * - 默认事件穿透
 */
export function setStatisticContainerStyle(container: HTMLElement, style: Partial<CSSStyleDeclaration>) {
  container.style['pointer-events'] = 'none';
  each(style, (v, k) => {
    if (k && v) {
      container.style[k] = v;
    }
  });
}

/**
 * 渲染环图 html-annotation（默认 position 居中 [50%, 50%]）
 * @param chart
 * @param options
 * @param meta 字段元信息
 * @param {optional} datum 当前的元数据
 */
export const renderStatistic = (chart: View, options: { statistic: Statistic; plotType: string }, datum?: Datum) => {
  const { statistic, plotType } = options;
  const { title: titleOpt, content: contentOpt } = statistic;

  [titleOpt, contentOpt].forEach((option, idx) => {
    if (!option) {
      return;
    }
    let transform = '';
    if (idx === 0) {
      transform = contentOpt ? 'translate(-50%, -100%)' : 'translate(-50%, -50%)';
    } else {
      transform = titleOpt ? 'translate(-50%, 0)' : 'translate(-50%, -50%)';
    }
    const style = isFunction(option.style) ? option.style(datum) : option.style;

    chart.annotation().html({
      position: ['50%', '50%'],
      html: (container, view) => {
        const coordinate = view.getCoordinate();
        let containerW = 0;
        if (plotType === 'pie' || plotType === 'ring-progress') {
          containerW = coordinate.getRadius() * coordinate.innerRadius * 2;
        } else if (plotType === 'liquid') {
          const liquidShape = get(view.geometries, [0, 'elements', 0, 'shape']);
          if (liquidShape) {
            // 获取到水波图边框大小
            const path = (liquidShape as IGroup).find((t) => t.get('name') === 'wrap');
            const { width } = path.getCanvasBBox();
            containerW = width;
          }
        } else if (!containerW) {
          // 保底方案
          containerW = coordinate.getWidth();
        }
        setStatisticContainerStyle(container, {
          width: `${containerW}px`,
          transform,
          // user's style setting has high priority
          ...adapteStyle(style),
        });

        const filteredData = view.getData();
        if (option.customHtml) {
          return option.customHtml(container, view, datum, filteredData);
        }

        let text = option.content;
        if (option.formatter) {
          text = option.formatter(datum, filteredData);
        }
        // todo G2 层修复可以返回空字符串 & G2 层修复允许返回非字符串的内容，比如数值 number
        return text ? (isString(text) ? text : `${text}`) : '<div></div>';
      },
      // @ts-ignore
      key: `${idx === 0 ? 'top' : 'bottom'}-statistic`,
      ...pick(option, ['offsetX', 'offsetY', 'rotate', 'style', 'formatter']) /** 透传配置 */,
    });
  });
};

/**
 * 渲染 html-annotation for gauge (等不规则 plot), 默认 position 居中居底 [50%, 100%]）
 * @param chart
 * @param options
 * @param meta 字段元信息
 * @param {optional} datum 当前的元数据
 */
export const renderGaugeStatistic = (chart: View, options: { statistic: Statistic }, datum?: Datum) => {
  const { statistic } = options;
  const { title: titleOpt, content: contentOpt } = statistic;

  [titleOpt, contentOpt].forEach((option) => {
    if (!option) {
      return;
    }
    const style = isFunction(option.style) ? option.style(datum) : option.style;
    chart.annotation().html({
      position: ['50%', '100%'],
      html: (container, view) => {
        const coordinate = view.getCoordinate();
        // 弧形的坐标
        const polarCoord = view.views[0].getCoordinate();
        const polarCenter = polarCoord.getCenter();
        const polarRadius = polarCoord.getRadius();
        const polarMaxY = Math.max(Math.sin(polarCoord.startAngle), Math.sin(polarCoord.endAngle)) * polarRadius;
        const offsetY = polarCenter.y + polarMaxY - coordinate.y.start - parseFloat(get(style, 'fontSize', 0));

        const containerWidth = coordinate.getRadius() * coordinate.innerRadius * 2;
        setStatisticContainerStyle(container, {
          width: `${containerWidth}px`,
          transform: `translate(-50%, ${offsetY}px)`,
          // user's style setting has high priority
          ...adapteStyle(style),
        });

        const filteredData = view.getData();
        if (option.customHtml) {
          return option.customHtml(container, view, datum, filteredData);
        }

        let text = option.content;
        if (option.formatter) {
          text = option.formatter(datum, filteredData);
        }

        // todo G2 层修复可以返回空字符串 & G2 层修复允许返回非字符串的内容，比如数值 number
        return text ? (isString(text) ? text : `${text}`) : '<div></div>';
      },
      ...pick(option, ['offsetX', 'offsetY', 'rotate', 'style', 'formatter']) /** 透传配置 */,
    });
  });
};
