import React, { useState } from 'react';
import { Container, SvgWrapper } from 'app/shared/modules/chart/core';
import { generateStackedBars } from 'app/shared/modules/chart/bar/compute';
import { Grid } from 'app/shared/modules/chart/core/axes';
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 { maxBy, round } from 'lodash';
import { FillableBar } from 'app/shared/modules/chart/bar/FillableBar';
import { useDispatch, useSelector } from 'react-redux';
import { dashboardSetCurrentPoolKeyFigures } from 'app/modules/dashboard/store/dashboard.actions';
import { getDashboardChartData } from 'app/modules/dashboard/store/dashboard.selectors';
import { getScreenWidth } from 'app/shared/store/ui/uiSelectors';
import { Spacings } from 'app/shared/types/common.types';
import { UI } from 'app/shared/store/ui/ui.constants';
import { Tooltip } from 'app/shared/modules/chart/core/tooltip/Tooltip';
import moneyPipe from 'app/shared/pipes/money.pipe';
import { DashboardChartTooltip } from './dashboardChartTooltip';
import datePipe from 'app/shared/pipes/date.pipe';

export interface Props {
  width: number;
  height: number;
  margin?: Spacings;
  gridPadding?: number;
  tickCount?: number;
  paddingRight?: number;
}

const DashboardChart = ({
  margin = { top: 10, right: 15, bottom: 30, left: 40 },
  gridPadding = 16,
  tickCount = 4,
  paddingRight = 16,
  width,
  height,
}: Props) => {
  const chartData = useSelector(getDashboardChartData);
  const { maxValue, barSeries, selectedId } = chartData;
  const isLargeScreen = useSelector(getScreenWidth) >= UI.BREAK_POINTS.LG;
  const [ tooltip, setTooltip ] = useState({
    isVisible: false,
    content: {
      date: '',
      earnings: '',
      fixed: null,
      isSelected: false,
    },
    position: {},
  });

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

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

  const calcWidth = width - margin.left - margin.right - gridPadding;
  const calcHeight = height - margin.top - margin.bottom - gridPadding;

  const xScaleStartOffset = 10;
  const yAxisTextOffset = 3;

  const barWidth = 16;

  const yTicksValues = computeTicksValues(maxValue, tickCount);
  const maxTickValue = maxBy(yTicksValues);
  const maxScale = maxValue > maxTickValue? maxValue : maxTickValue;
  const options = {
    barSeries,
    keys: [ 'value' ],
    minValue: 0,
    maxValue: maxScale,
    width: calcWidth,
    height: calcHeight,
    padding: 0,
    innerPadding: 0,
  };

  const barChart = generateStackedBars(options);
  const centerOffset = (calcWidth - ((barChart.xScale((barSeries.length - 1).toString()) ?? 0) + (barChart.xScale('0') ?? 0))) / 2 - xScaleStartOffset;

  const horizontalTicks = computeAxisTicks({
    width: calcWidth,
    height: calcHeight,
    scale: barChart.xScale,
    values: barChart.xScale.domain(),
    getLabel: (index) => barSeries[index].label.toString(),
    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,
    position: 'left',
  });

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

  const bars = barChart.bars.map((bar, index) => {
    const roundedFilledHeight = round(bar.height * round(bar.data.data.filledRatio / 100, 2));
    bar.filledHeight = roundedFilledHeight !== null && roundedFilledHeight !== undefined
      ? roundedFilledHeight
      : bar.height;

    const onEnter = () => {
      const tooltipPosition = isLargeScreen || index < 1 ? {
        left: bar.x + tooltipOffset.left,
        bottom: tooltipOffset.bottom,
      } : {
        right: width - bar.x - tooltipOffset.right,
        bottom: tooltipOffset.bottom,
      };

      const tooltipContent = {
        date: datePipe.formatShortMonthWithYear(bar.data.data.date),
        earnings: moneyPipe.format(bar.data.value),
        fixed: bar.data.data.filledRatio === 100 || bar.data.data.filledRatio === null
          ? null
          : `${bar.data.data.filledRatio}% fixed`,
        isSelected: bar.data.data.id === selectedId,
      };
      showTooltip({ tooltipPosition, tooltipContent });
    };

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

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

  return (
    <div>
      <Container>
        {() => (
          <div>
            {/*@ts-ignore*/}
            <SvgWrapper height={height} margin={margin} width={width}>
              <pattern id="pattern-stripe"
                width="8" height="8"
                patternUnits="userSpaceOnUse"
                patternTransform="rotate(45)">
                <rect className="u-pattern-stripes" width="1" height="8" transform="translate(0,0)"/>
                <rect className="u-pattern-stripes" width="1" height="8" transform="translate(4,0)"/>
              </pattern>
              <pattern id="pattern-stripe-selected"
                width="8" height="8"
                patternUnits="userSpaceOnUse"
                patternTransform="rotate(45)">
                <rect className="u-pattern-stripes--selected" width="1" height="8" transform="translate(0,0)"/>
                <rect className="u-pattern-stripes--selected" width="1" height="8" transform="translate(4,0)"/>
              </pattern>
              <Axis {...verticalTicks} />
              <Group x={gridPadding} y={0}>
                <Group x={centerOffset} y={gridPadding}>
                  <Axis {...horizontalTicks} />
                </Group>
                <Grid width={calcWidth + paddingRight} height={calcHeight} xScale={null} yScale={barChart.yScale} yTicks={yTicksValues}/>
                <Group x={centerOffset} y={0}>
                  <g className="c-chart__bars">{bars}</g>
                </Group>
              </Group>
              <Group x={-margin.left + gridPadding} y={calcHeight + margin.top + yAxisTextOffset}>
                <text className={'c-chart__unit-label'}>
                  <tspan>USD</tspan>
                  <tspan x={0} dy={'1em'}>/DAY</tspan>
                </text>
              </Group>
            </SvgWrapper>
          </div>
        )}
      </Container>
      {/* @ts-ignore*/}
      <Tooltip isVisible={tooltip.isVisible} position={tooltip.position} aside>
        {() => <DashboardChartTooltip
          date={tooltip.content.date}
          earnings={tooltip.content.earnings}
          fixed={tooltip.content.fixed}
          isSelected={tooltip.content.isSelected}
        />}
      </Tooltip>
    </div>
  );
};

export { DashboardChart };
