import { jsx, Component, computeLayout, GroupStyleProps, TextStyleProps } from '@antv/f-engine';
import { ChartChildProps } from '../../chart';
import { isFunction } from '@antv/util';

interface LegendItem {
  /**
   * 标记颜色。
   */
  color?: string;
  /**
   * 名称。
   */
  name?: string;
  /**
   * 值。
   */
  value?: string | number;
  /**
   * 图例标记。
   */
  marker?: string;
  [key: string]: any;
}
export interface LegendProps {
  /**
   * 图例的显示位置。默认为 top。
   */
  position?: 'right' | 'left' | 'top' | 'bottom';
  /**
   * 布局模式：'uniform' 统一宽度（默认），'adaptive' 自适应宽度
   */

  layoutMode?: 'uniform' | 'adaptive';

  /**
   * 图例宽度 uniform 模式下生效
   */
  width?: number | string;
  /**
   * 图例高度
   */
  height?: number | string;
  /**
   * legend 和图表内容的间距
   */
  margin?: number | string;
  /**
   * 回调函数，用于格式化图例每项的文本显示。
   */
  itemFormatter?: (value, name) => string;
  /**
   * 图例项列表。
   */
  items?: LegendItem[];
  /**
   * 图例样式。
   */
  style?: GroupStyleProps;
  /**
   * 图例标记。
   */
  marker?: 'circle' | 'square' | 'line';
  /**
   * 用于设置图例项的样式
   */
  itemStyle?: GroupStyleProps;
  /**
   * 用于设置图例项的文本样式
   */
  nameStyle?: Omit<TextStyleProps, 'text'>;
  /**
   * 用于设置图例项的文本样式
   */
  valueStyle?: Omit<TextStyleProps, 'text'>;
  /**
   * value展示文案的前缀
   */
  valuePrefix?: string;
  /**
   * 是否可点击
   */
  clickable?: boolean;
  onClick?: (item: LegendItem) => void;
  clickMode?: 'filter' | 'highlight';
}

export default (View) => {
  return class Legend<IProps extends LegendProps = LegendProps> extends Component<
    IProps & ChartChildProps
  > {
    legendStyle: GroupStyleProps;
    itemWidth: Number;

    constructor(props) {
      super(props);
      this.state = {
        filtered: {},
        highlighted: {},
        items: [],
      };
    }

    getOriginItems() {
      const { chart } = this.props;
      return chart.getLegendItems();
    }

    getItems() {
      const { props, state } = this;
      const { filtered, highlighted } = state;
      const renderItems = props.items?.length ? props.items : this.getOriginItems();
      if (!renderItems) return null;
      return renderItems.map((item) => {
        const { tickValue } = item;
        return {
          ...item,
          filtered: filtered[tickValue],
          highlighted: highlighted[tickValue],
        };
      });
    }

    setItems(items) {
      this.setState({
        items,
      });
    }

    getMaxItemBox(node) {
      let maxItemWidth = 0;
      let maxItemHeight = 0;
      (node.children || []).forEach((child) => {
        const { layout } = child;
        const { width, height } = layout;

        maxItemWidth = Math.max(maxItemWidth, width);
        maxItemHeight = Math.max(maxItemHeight, height);
      });

      return {
        width: maxItemWidth,
        height: maxItemHeight,
      };
    }

    getItemBoxes(node) {
      return (node.children || []).map((child) => {
        const { layout } = child;
        const { width, height } = layout;

        return { width, height };
      });
    }
    // 计算 legend 的位置
    _init() {
      const { props, context } = this;
      const {
        // @ts-ignore
        layout: parentLayout,
        width: customWidth,
        height: customHeight,
        position = 'top',
        layoutMode = 'uniform',
      } = props;
      const items = this.getItems();
      if (!items || !items.length) return;
      const { left, top, width: layoutWidth, height: layoutHeight } = parentLayout;
      const width = context.px2hd(customWidth) || layoutWidth;
      const node = computeLayout(this, this.render());

      const { width: itemMaxWidth, height: itemMaxHeight } = this.getMaxItemBox(node);

      let lineCount, itemWidth;
      if (layoutMode === 'adaptive') {
        const labelBBoxes = this.getItemBoxes(node);
        let pos = 0;
        lineCount = 1;
        for (const { width: boxWidth } of labelBBoxes) {
          if (pos + boxWidth > width) {
            pos = boxWidth;
            lineCount++;
          } else {
            pos += boxWidth;
          }
        }
        itemWidth = undefined;
      } else {
        // uniform模式
        const lineMaxCount = Math.max(1, Math.floor(width / itemMaxWidth));
        const itemCount = items.length;
        lineCount = Math.ceil(itemCount / lineMaxCount);
        itemWidth = width / lineMaxCount;
      }

      const autoHeight = itemMaxHeight * lineCount;

      const style: GroupStyleProps = {
        left,
        top,
        width,
        // height 默认自适应
        height: undefined,
        flexDirection: 'row',
        flexWrap: 'wrap',
        alignItems: 'center',
        justifyContent: 'flex-start',
      };

      // 如果只有一行，2端对齐
      if (lineCount === 1) {
        style.justifyContent = 'space-between';
      }

      if (position === 'top') {
        style.height = customHeight ? customHeight : autoHeight;
      }
      if (position === 'left') {
        style.flexDirection = 'column';
        style.justifyContent = 'center';
        style.alignItems = layoutMode === 'adaptive' ? 'flex-start' : 'center';
        style.width = itemMaxWidth;
        style.height = customHeight ? customHeight : layoutHeight;
      }
      if (position === 'right') {
        style.flexDirection = 'column';
        style.alignItems = 'flex-start';
        style.justifyContent = 'center';
        style.left = left + (width - itemMaxWidth);
        style.width = itemMaxWidth;
        style.height = customHeight ? customHeight : layoutHeight;
      }
      if (position === 'bottom') {
        style.top = top + (layoutHeight - autoHeight);
        style.height = customHeight ? customHeight : autoHeight;
      }

      this.itemWidth = itemWidth;
      this.legendStyle = style;
    }

    updateCoord() {
      const { context, props, legendStyle } = this;
      const { position = 'top', margin = '30px', chart } = props;
      const { width, height } = legendStyle;
      const marginNumber = context.px2hd(margin);

      chart.updateCoordFor(this, {
        position,
        width: width + marginNumber,
        height: height + marginNumber,
      });
    }

    willMount() {
      const items = this.getItems();
      if (!items || !items.length) return;
      this._init();
      this.updateCoord();
    }

    didMount() {
      // this._initEvent();
    }

    willUpdate(): void {
      const items = this.getItems();
      if (!items || !items.length) return;
      this._init();
      this.updateCoord();
    }

    _onclick = (item) => {
      const { props } = this;
      const { chart, clickable = true, onClick, clickMode = 'filter' } = props;
      if (!clickable) return;

      const clickItem = item.currentTarget;
      if (!clickItem) return;

      // @ts-ignore
      const dataItem = clickItem.config['data-item'];
      if (!dataItem) return;

      if (isFunction(onClick)) {
        onClick(dataItem);
      }

      const { field, tickValue } = dataItem;
      const { filtered: prevFiltered, highlighted: preHighlighted } = this.state;
      const filtered = {
        ...prevFiltered,
        [tickValue]: !prevFiltered[tickValue],
      };

      if (clickMode === 'filter') {
        this.setState({
          filtered,
        });
        chart.filter(field, (value) => {
          return !filtered[value];
        });
      } else if (clickMode === 'highlight') {
        const highlighted = {
          [tickValue]: !preHighlighted[tickValue],
        };
        this.setState({
          highlighted,
        });
        chart.highlight(
          field,
          preHighlighted[tickValue]
            ? null
            : (value) => {
                return highlighted[value];
              }
        );
      }
    };

    render() {
      const { props, itemWidth, legendStyle } = this;
      const items = this.getItems();

      if (!items || !items.length) {
        return null;
      }

      return (
        <View
          {...props}
          items={items}
          itemWidth={itemWidth}
          style={{
            ...legendStyle,
            ...props.style,
          }}
          onClick={this._onclick}
        />
      );
    }
  };
};
