import { max } from 'd3-array';
import {
  ScaleBand,
  scaleBand,
  ScaleLinear,
  scaleLinear
} from 'd3-scale';
import { select } from 'd3-selection';
import React, { CSSProperties, Fragment, MutableRefObject, useEffect, useRef } from 'react';
import ChartTooltip from '../chart-tooltip/chart-tooltip';
import './bar-chart.scss';

export type barChartDataType = {
  label?: string;
  value: number;
  date: string;
  borderColor?: string;
  borderWidth?: number;
  backgroundColor?: string;
};
/* eslint-disable-next-line */
export interface BarChartProps {
  data: barChartDataType[]; // data is collection of array
  size: number[]; // size represents here width and height of the bar chart
  paddingInner?: number; // its consider to distance between bars
  style?: CSSProperties; // its consider to add style to change svg
}
const barChartDataTypeDefault: barChartDataType[] = [
  {
    label: '12/12/2002',
    value: 1,
    borderColor: '#fff',
    borderWidth: 2,
    backgroundColor: '#555',
    date: '10/10/2002',
  },
];
/**
 *
 * @param  BarChartProps;
 * @component BarChart;
 * @description its dynamic and responsive bar chart
 * @created by Md. Rakibul Alam
 */
export const BarChart = ({
  data = barChartDataTypeDefault,
  size = [200, 200],
  paddingInner = 0.1,
  style,
}: BarChartProps) => {
  const chartRef: MutableRefObject<undefined> = useRef();
  const tooltipRef: MutableRefObject<undefined> = useRef();
  const [width, height] = size;

  useEffect(() => {
    const node = chartRef.current; // current ref dom as here is node
    const tooltipNode = tooltipRef.current; // current ref dom as here is tooltip
    const sortDataByDate = data.sort(
      (a: barChartDataType, b: barChartDataType): any =>
        (new Date(a.date) as any) - (new Date(b.date) as any)
    );
    // const dataLenght = sortDataByDate.length; // take the data length for the optimize performance

    const valueMax: number = max(sortDataByDate.map(({ value }) => value));
    // const dateMax: Date = max(data.map(({ date }) => new Date(date)));
    // const dateMin: Date = min(data.map(({ date }) => new Date(date)));

    const xScaleBand: ScaleBand<string> = scaleBand()
      .domain(sortDataByDate.map((d) => d.date))
      .rangeRound([0, width])
      .paddingInner(paddingInner)
      .paddingOuter(0);

    const yScale: ScaleLinear<number, number, never> = scaleLinear()
      .domain([0, valueMax])
      .range([0, height]);

    select(node).selectAll('rect').data(sortDataByDate).enter().append('rect');

    select(node).selectAll('rect').data(sortDataByDate).exit().remove();

    // const deltaWidth: number = (dataLenght - 1) * barGap; // its consider to fix the bar witdh removing extra width from the current width. its always be considered total width minus one
    // const barWidth: number = (width - deltaWidth) / dataLenght; // find the exact bar witdh
    const tooltip = select(tooltipNode)
    // .style("position", "absolute")
    // .style("z-index", "10")
    // .style("visibility", "hidden");

    select(node)
      .selectAll('rect')
      .data(sortDataByDate)
      .style('fill', ({ backgroundColor }) => backgroundColor || '#000')
      .attr('x', ({ date }) => xScaleBand(date)) // added barWidth for change x position from the current position first time i=0, so there is no need to change first positions
      .attr('y', ({ value }) => height - yScale(value))
      .attr('height', ({ value }) => yScale(value))
      .attr('width', xScaleBand.bandwidth())
      .on("mouseover", () => tooltip.style("visibility", "visible"))
      .on("mousemove", (event, { label }) => tooltip.style("top", (event.pageY - 10) + "px").style("left", (event.pageX + 10) + "px").text(label))
      .on("mouseout", () => tooltip.style("visibility", "hidden"));

  }, []);
  return <Fragment>
    <svg style={style} ref={chartRef} width={width} height={height}></svg>
    <ChartTooltip ref={tooltipRef} />
  </Fragment>
};

export default BarChart;
