import React, { useState } from 'react';
import { Container, ResponsiveWrapper, SvgWrapper } from 'app/shared/modules/chart/core';
import { convertSeriesToLine } from 'app/shared/modules/chart/line/compute/line';
import { generateStackedBars } from 'app/shared/modules/chart/bar/compute';
import { Grid } from 'app/shared/modules/chart/core/axes';
import { LineChart } from 'app/shared/modules/chart/line/LineChart';
import { Bar } from 'app/shared/modules/chart/bar/Bar';
import { Axis } from 'app/shared/modules/chart/core/axes/Axis';
import { computeAxisTicks, computeTicksValues } from 'app/shared/modules/chart/core/axes/compute/cartesian';
import { Group } from 'app/shared/modules/chart/core/containers/Group';
import { Tooltip } from 'app/shared/modules/chart/core/tooltip/Tooltip';
import { flatten, maxBy } from 'lodash';
import { selectTceChartData } from '../../store/tceChart.selectors';
import { useDispatch, useSelector } from 'react-redux';
import { clearEarningsPageScroll, selectAggregation } from '../../store/earnings.actions';
import { TceChartTooltip } from './tceChartTooltip';
import { getScreenWidth } from 'app/shared/store/ui/uiSelectors';
import { UI } from 'app/shared/store/ui/ui.constants';

export interface Props {
  gridPadding?: number,
  margin?: { top: number, right: number, bottom: number, left: number },
  tickCount?: number,
}

export const TceChart = ({
  gridPadding = 10,
  tickCount = 4,
  margin = { top: 5, right: 0, bottom: 30, left: 40 },
}: Props) => {
  const [ tooltip, setTooltip ] = useState({
    isVisible: false,
    position: {},
    content: {
      title: '',
      tce: '',
      mode: '',
      benchmark: '',
    },
  });

  const [ shouldAnimate, setAnimation ] = useState(true);

  const showTooltip = (data) => {
    setTooltip({
      isVisible: true,
      content: data.content,
      position: data.position,
    });
  };

  const hideTooltip = () => {
    setTooltip({
      ...tooltip,
      isVisible: false,
    });
  };

  const handleLineAnimationEnd = () => {
    setAnimation(false);
  };

  const dispatch = useDispatch();

  const chartData = useSelector(selectTceChartData);
  const {
    barSeries,
    linesSeries,
    selectedId,
  } = chartData;

  const isLargeScreen = useSelector(getScreenWidth) >= UI.BREAK_POINTS.LG;

  return (
    <ResponsiveWrapper>
      {
        (size) => {
          if (!barSeries || barSeries.length === 0) {
            return (
              <div className="c-chart__no-data-label">No data available.</div>
            );
          }

          const onClick = (currentBar) => {
            dispatch(selectAggregation(currentBar.data.id));
            dispatch(clearEarningsPageScroll());
          };
          const calcWidth = Number(size?.width) - margin.left - margin.right - gridPadding;
          const calcHeight = Number(size?.height) - margin.top - margin.bottom - gridPadding;
          const { position, content, isVisible } = tooltip;

          let lineValues = flatten(linesSeries.map((c) => c.items)).map((d) => d.value);
          let barValues = barSeries.map((d) => d.value);
          let maxValue = maxBy(barValues.concat(lineValues));
          const yTicksValues = computeTicksValues(maxValue, tickCount);
          let maxTickValue = maxBy(yTicksValues);
          let maxScale = maxValue > maxTickValue? maxValue : maxTickValue;
          const options = {
            barSeries,
            keys: [ 'value' ],
            minValue: 0,
            maxValue: maxScale,
            width: calcWidth,
            height: calcHeight,
            padding: 0,
            innerPadding: 0,
          };

          const barWidth = 12;

          const barChart = generateStackedBars(options);
          const lineChart = convertSeriesToLine(linesSeries, barChart.xScale, barChart.yScale);
          const centerOffset = (calcWidth - (barChart.xScale((barSeries.length - 1).toString())! + barChart.xScale('0')!)) / 2;

          const horizontalTicks = computeAxisTicks({
            width: calcWidth,
            height: calcHeight,
            scale: barChart.xScale,
            values: barChart.xScale.domain(),
            getLabel: (index) => barSeries[index].label,
            getSubLabel: (index) => barSeries[index].subLabel,
            position: 'bottom',
            isSelected: (value) => barSeries[value].id === selectedId,
          });

          const verticalTicks = computeAxisTicks({
            width: calcWidth,
            height: calcHeight,
            scale: barChart.yScale,
            values: yTicksValues,
            getLabel: (value) => value.toLocaleString('en-US'),
            position: 'left',
          });

          const tooltipOffset = {
            bottom: 60,
            left: centerOffset + gridPadding + margin.left + barWidth / 2 + 8,
            right: centerOffset + gridPadding + margin.right + barWidth / 2 + 20,
          };

          const getTooltipPosition = (x, index) => isLargeScreen || index < 2 ? {
            left: x + tooltipOffset.left,
            bottom: tooltipOffset.bottom,
          } : {
            right: Number(size?.width) - x - tooltipOffset.right,
            bottom: tooltipOffset.bottom,
          };

          const bars = barChart.bars.map((bar, index) => {
            const onEnter = () => {
              showTooltip({ position: getTooltipPosition(bar.x, index), content: bar.data.data.popover });
            };

            const onLeave = () => {
              hideTooltip();
            };

            return (
              <Bar
                index={index}
                key={bar.key}
                {...bar}
                onEnter={onEnter}
                onLeave={onLeave}
                selected={bar.data.data.id === selectedId}
                onClick={onClick}
                width={barWidth}
                animate
              />
            );
          });

          return (
            <div>
              <Container>
                {() => {
                  const onEnterDot = (point, index) => {
                    showTooltip({ position: getTooltipPosition(point.x, index), content: point.item.popover });
                  };
                  const onLeaveDot = () => {
                    hideTooltip();
                  };
                  return (
                    <div>
                      {/*@ts-ignore*/}
                      <SvgWrapper height={Number(size?.height)} margin={margin} width={Number(size?.width)}>
                        <Axis {...verticalTicks} />
                        <Group x={gridPadding} y={0}>
                          <Group x={centerOffset} y={gridPadding}>
                            <Axis {...horizontalTicks} />
                          </Group>
                          <Grid
                            width={calcWidth}
                            height={calcHeight}
                            xScale={null}
                            yScale={barChart.yScale}
                            yTicks={yTicksValues}
                          />
                          <Group x={centerOffset} y={0}>
                            <g className="c-chart__bars">{bars}</g>
                            <LineChart
                              // @ts-ignore
                              series={lineChart}
                              onEnter={onEnterDot}
                              onLeave={onLeaveDot}
                              animate={shouldAnimate}
                              onAnimationEnd={handleLineAnimationEnd}
                            />
                          </Group>
                        </Group>
                      </SvgWrapper>
                    </div>
                  );
                }}
              </Container>
              {/*@ts-ignore*/}
              <Tooltip isVisible={isVisible} position={position} aside>
                {() => <TceChartTooltip
                  title={content.title}
                  tce={content.tce}
                  mode={content.mode}
                  benchmark={content.benchmark}
                />}
              </Tooltip>
            </div>);
        }
      }
    </ResponsiveWrapper>
  );
};
