import { interaction, state, theme } from '../../adaptor/common';
import { edge, polygon } from '../../adaptor/geometries';
import { Params } from '../../core/adaptor';
import { addViewAnimation, flow, getAllGeometriesRecursively, pick, transformDataToNodeLinkData } from '../../utils';
import { chordLayout } from '../../utils/transform/chord';
import { EDGE_COLOR_FIELD, NODE_COLOR_FIELD, X_FIELD, Y_FIELD } from './constant';
import { ChordOptions } from './types';

function transformData(params: Params<ChordOptions>): Params<ChordOptions> {
  // 将弦图数据放到ext中，nodeGeometry edgeGeometry使用

  const { options } = params;
  const { data, sourceField, targetField, weightField, nodePaddingRatio, nodeWidthRatio, rawFields = [] } = options;

  // 将数据转换为node link格式
  const chordLayoutInputData = transformDataToNodeLinkData(data, sourceField, targetField, weightField);

  const { nodes, links } = chordLayout({ weight: true, nodePaddingRatio, nodeWidthRatio }, chordLayoutInputData);

  // 1. 生成绘制node使用数据
  const nodesData = nodes.map((node) => {
    return {
      ...pick(node, ['id', 'x', 'y', 'name', ...rawFields]),
      isNode: true,
    };
  });

  // 2. 生成 edge 使用数据 （同桑基图）
  const edgesData = links.map((link) => {
    return {
      source: link.source.name,
      target: link.target.name,
      name: link.source.name || link.target.name,
      ...pick(link, ['x', 'y', 'value', ...rawFields]),
      isNode: false,
    };
  });

  return {
    ...params,
    ext: {
      ...params.ext,
      // 将chordData放到ext中，方便下面的geometry使用
      chordData: { nodesData, edgesData },
    },
  };
}

/**
 * scale配置
 * @param params 参数
 */
function scale(params: Params<ChordOptions>): Params<ChordOptions> {
  const { chart } = params;
  chart.scale({
    x: { sync: true, nice: true },
    y: { sync: true, nice: true, max: 1 },
    [NODE_COLOR_FIELD]: { sync: 'color' },
    [EDGE_COLOR_FIELD]: { sync: 'color' },
  });
  return params;
}

/**
 * axis配置
 * @param params 参数
 */
function axis(params: Params<ChordOptions>): Params<ChordOptions> {
  const { chart } = params;
  chart.axis(false);
  return params;
}

/**
 * legend配置
 * @param params 参数
 */
function legend(params: Params<ChordOptions>): Params<ChordOptions> {
  const { chart } = params;
  chart.legend(false);
  return params;
}

/**
 * tooltip配置
 * @param params 参数
 */
function tooltip(params: Params<ChordOptions>): Params<ChordOptions> {
  const { chart, options } = params;
  const { tooltip } = options;

  chart.tooltip(tooltip);
  return params;
}

/**
 * coordinate配置
 * @param params 参数
 */
function coordinate(params: Params<ChordOptions>): Params<ChordOptions> {
  const { chart } = params;
  chart.coordinate('polar').reflect('y');
  return params;
}

/**
 * nodeGeometry配置
 * @param params 参数
 */
function nodeGeometry(params: Params<ChordOptions>): Params<ChordOptions> {
  // node view
  const { chart, options } = params;
  const { nodesData } = params.ext.chordData;
  const { nodeStyle, label, tooltip } = options;

  const nodeView = chart.createView();
  nodeView.data(nodesData);

  // 面
  polygon({
    chart: nodeView,
    options: {
      xField: X_FIELD,
      yField: Y_FIELD,
      seriesField: NODE_COLOR_FIELD,
      polygon: {
        style: nodeStyle,
      },
      label,
      tooltip,
    },
  });
  return params;
}

/**
 * edgeGeometry配置
 * @param params 参数
 */
function edgeGeometry(params: Params<ChordOptions>): Params<ChordOptions> {
  const { chart, options } = params;
  const { edgesData } = params.ext.chordData;
  const { edgeStyle, tooltip } = options;

  const edgeView = chart.createView();
  edgeView.data(edgesData);

  // edge
  const edgeOptions = {
    xField: X_FIELD,
    yField: Y_FIELD,
    seriesField: EDGE_COLOR_FIELD,
    edge: {
      style: edgeStyle,
      shape: 'arc',
    },
    tooltip,
  };
  edge({
    chart: edgeView,
    options: edgeOptions,
  });
  return params;
}

function animation(params: Params<ChordOptions>): Params<ChordOptions> {
  const { chart, options } = params;
  const { animation } = options;

  addViewAnimation(chart, animation, getAllGeometriesRecursively(chart));

  return params;
}

/**
 * 弦图适配器
 * @param chart
 * @param options
 */
export function adaptor(params: Params<ChordOptions>) {
  // flow 的方式处理所有的配置到 G2 API
  return flow(
    theme,
    transformData,
    coordinate,
    scale,
    axis,
    legend,
    tooltip,
    edgeGeometry,
    nodeGeometry,
    interaction,
    state,
    animation
  )(params);
}
