import { memo } from 'react';
import { Group } from '@visx/group';
import { Treemap, stratify } from '@visx/hierarchy';
import {
  treemapSquarify,
  treemapBinary,
  treemapDice,
  treemapResquarify,
  treemapSlice,
  treemapSliceDice,
} from '@visx/hierarchy';

import { call } from '../../utils';
import { TextLabelSettings } from '../../types';
import { TooltipBinder } from 'hooks/useTooltip';

export const TILE_METHODS = {
  treemapSquarify,
  treemapBinary,
  treemapDice,
  treemapResquarify,
  treemapSlice,
  treemapSliceDice,
};

export function tileFactory(type: string | undefined) {
  return type
    ? (TILE_METHODS as Record<string, any>)[type]
    : TILE_METHODS['treemapSquarify'];
}

const COLORS = [
  'rgb(232, 193, 160)',
  'rgb(241, 225, 91)',
  'rgb(97, 205, 187)',
  'rgb(151, 227, 213)',
  'rgb(232, 168, 56)',
  'rgb(244, 117, 96)', // red
];

export type TreeMapDatum = {
  id: string;
  parent: string;
  label: string;
  value: number;
};

export type TreeMapSVGProps = TextLabelSettings & {
  data: TreeMapDatum[];
  width: number;
  height: number;
  tileMethod?: string;
  bindTooltip?: TooltipBinder<TreeMapDatum>;
};

export const defaultProps = {
  parentSelector: 'parent',
  valueSelector: 'value',
  tileMethod: 'treemapSquarify',
  textLabel: true,
  textLabelSize: 12,
  // textLabelColor,
};

function TreeMapSVG({
  data,
  tileMethod,
  width,
  height,
  bindTooltip,
  textLabel,
  textLabelSize,
  textLabelColor,
}: TreeMapSVGProps & typeof defaultProps) {
  const margin = {
    top: 0,
    left: 0,
    right: 0,
    bottom: 0,
  };

  const parentSelector = (d: TreeMapDatum) => d.parent;
  const valueSelector = (d: TreeMapDatum) => d.value;

  const chartWidth = width - margin.left - margin.right;
  const chartHeight = height - margin.top - margin.bottom;

  const tree = stratify<TreeMapDatum>()
    .id((d) => d.id)
    .parentId(parentSelector)(data)
    .sum((d) => valueSelector(d) || 0)
    // .sum((d) => {
    //   if (parentSelector(d)) {
    //     return valueSelector(d);
    //   } else {
    //     return 0;
    //   }
    // })
    // .each((d) => (d.value = valueSelector(d.data)))
    .sort((a, b) => (b.value || 0) - (a.value || 0));

  return (
    <svg width={width} height={height}>
      <Treemap
        root={tree}
        top={margin.top}
        size={[chartWidth, chartHeight]}
        tile={tileFactory(tileMethod)}
        padding={4}
        round
      >
        {(treemap) => (
          <Group>
            {treemap
              .descendants()
              // .reverse()
              .map((node, i) => {
                const top = node.y0 + margin.top;
                const left = node.x0 + margin.left;

                const width = node.x1 - node.x0;
                const height = node.y1 - node.y0;

                const data = node.data;
                // const label = node.data.value + '';
                const label = data.label;

                // const ontop = tree.height === node.depth;
                const highest = node.children === undefined;
                const fit = label.length * 2 < width;
                const tooltipProps = call(bindTooltip, data);

                return (
                  <Group {...tooltipProps} top={top} left={left} key={i}>
                    <rect
                      width={width}
                      height={height}
                      fill={COLORS[node.depth]}
                    />
                    {textLabel && highest && fit && (
                      <text
                        x={width / 2}
                        y={height / 2}
                        fill={textLabelColor}
                        fontSize={textLabelSize}
                        textAnchor={'middle'}
                        dominantBaseline={'central'}
                      >
                        {label}
                      </text>
                    )}
                  </Group>
                );
              })}
          </Group>
        )}
      </Treemap>
    </svg>
  );
}

TreeMapSVG.defaultProps = defaultProps;

export default memo(TreeMapSVG);
