// @ts-strict-ignore
import React from 'react';

import { css } from 'glamor';
import {
  AreaChart,
  Area,
  CartesianGrid,
  XAxis,
  YAxis,
  Tooltip,
  ResponsiveContainer,
} from 'recharts';

import * as monthUtils from 'loot-core/src/shared/months';
import {
  amountToCurrency,
  amountToCurrencyNoDecimal,
} from 'loot-core/src/shared/util';
import { type SpendingEntity } from 'loot-core/src/types/models/reports';

import { usePrivacyMode } from '../../../hooks/usePrivacyMode';
import { theme } from '../../../style';
import { type CSSProperties } from '../../../style';
import { AlignedText } from '../../common/AlignedText';
import { Container } from '../Container';
import { numberFormatterTooltip } from '../numberFormatter';

type PayloadItem = {
  value: number;
  payload: {
    totalAssets: number | string;
    totalDebts: number | string;
    totalTotals: number | string;
    day: string;
    months: {
      date: string;
      cumulative: number | string;
    };
  };
};

type CustomTooltipProps = {
  active?: boolean;
  payload?: PayloadItem[];
  balanceTypeOp?: string;
  thisMonth?: string;
  lastYear?: string;
  selection?: string;
};

const CustomTooltip = ({
  active,
  payload,
  balanceTypeOp,
  thisMonth,
  lastYear,
  selection,
}: CustomTooltipProps) => {
  if (active && payload && payload.length) {
    const comparison =
      selection === 'average'
        ? payload[0].payload[selection] * -1
        : payload[0].payload.months[selection].cumulative * -1;
    return (
      <div
        className={`${css({
          zIndex: 1000,
          pointerEvents: 'none',
          borderRadius: 2,
          boxShadow: '0 1px 6px rgba(0, 0, 0, .20)',
          backgroundColor: theme.menuBackground,
          color: theme.menuItemText,
          padding: 10,
        })}`}
      >
        <div>
          <div style={{ marginBottom: 10 }}>
            <strong>
              Day:{' '}
              {Number(payload[0].payload.day) >= 28
                ? '28+'
                : payload[0].payload.day}
            </strong>
          </div>
          <div style={{ lineHeight: 1.5 }}>
            {payload[0].payload.months[thisMonth].cumulative ? (
              <AlignedText
                left="This month:"
                right={amountToCurrency(
                  payload[0].payload.months[thisMonth].cumulative * -1,
                )}
              />
            ) : null}
            {['cumulative'].includes(balanceTypeOp) && (
              <AlignedText
                left={
                  selection === 'average'
                    ? 'Average'
                    : selection === lastYear
                      ? 'Last year'
                      : 'Last month'
                }
                right={amountToCurrency(comparison)}
              />
            )}
            {payload[0].payload.months[thisMonth].cumulative ? (
              <AlignedText
                left="Difference:"
                right={amountToCurrency(
                  payload[0].payload.months[thisMonth].cumulative * -1 -
                    comparison,
                )}
              />
            ) : null}
          </div>
        </div>
      </div>
    );
  }
};

type SpendingGraphProps = {
  style?: CSSProperties;
  data: SpendingEntity;
  compact?: boolean;
  mode: string;
};

export function SpendingGraph({
  style,
  data,
  compact,
  mode,
}: SpendingGraphProps) {
  const privacyMode = usePrivacyMode();
  const balanceTypeOp = 'cumulative';
  const thisMonth = monthUtils.currentMonth();
  const lastMonth = monthUtils.subMonths(monthUtils.currentMonth(), 1);
  const lastYear = monthUtils.prevYear(monthUtils.currentMonth());
  let selection;
  switch (mode) {
    case 'average':
      selection = 'average';
      break;
    case 'lastYear':
      selection = lastYear;
      break;
    default:
      selection = lastMonth;
      break;
  }

  const thisMonthMax = data.intervalData.reduce((a, b) =>
    a.months[thisMonth][balanceTypeOp] < b.months[thisMonth][balanceTypeOp]
      ? a
      : b,
  ).months[thisMonth][balanceTypeOp];
  const selectionMax =
    selection === 'average'
      ? data.intervalData[27].average
      : data.intervalData.reduce((a, b) =>
          a.months[selection][balanceTypeOp] <
          b.months[selection][balanceTypeOp]
            ? a
            : b,
        ).months[selection][balanceTypeOp];
  const maxYAxis = selectionMax > thisMonthMax;
  const dataMax = Math.max(
    ...data.intervalData.map(i => i.months[thisMonth].cumulative),
  );
  const dataMin = Math.min(
    ...data.intervalData.map(i => i.months[thisMonth].cumulative),
  );

  const tickFormatter = tick => {
    if (!privacyMode) return `${amountToCurrencyNoDecimal(tick)}`; // Formats the tick values as strings with commas
    return '...';
  };

  const gradientOffset = () => {
    if (!dataMax || dataMax <= 0) {
      return 0;
    }
    if (!dataMin || dataMin >= 0) {
      return 1;
    }

    return dataMax / (dataMax - dataMin);
  };

  const getVal = (obj, month) => {
    if (month === 'average') {
      return obj[month] && -1 * obj[month];
    } else {
      return (
        obj.months[month][balanceTypeOp] &&
        -1 * obj.months[month][balanceTypeOp]
      );
    }
  };

  const getDate = obj => {
    return Number(obj.day) >= 28 ? '28+' : obj.day;
  };

  return (
    <Container
      style={{
        ...style,
        ...(compact && { height: 'auto' }),
      }}
    >
      {(width, height) =>
        data.intervalData && (
          <ResponsiveContainer>
            <div>
              {!compact && <div style={{ marginTop: '15px' }} />}
              <AreaChart
                width={width}
                height={height}
                data={data.intervalData}
                margin={{
                  top: 10,
                  right: 0,
                  left: 0,
                  bottom: 0,
                }}
              >
                {compact ? null : (
                  <CartesianGrid strokeDasharray="3 3" vertical={false} />
                )}
                {compact ? null : (
                  <XAxis
                    dataKey={val => getDate(val)}
                    tick={{ fill: theme.pageText }}
                    tickLine={{ stroke: theme.pageText }}
                  />
                )}
                {compact ? null : (
                  <YAxis
                    dataKey={val =>
                      getVal(val, maxYAxis ? thisMonth : selection)
                    }
                    domain={[0, 'auto']}
                    tickFormatter={tickFormatter}
                    tick={{ fill: theme.pageText }}
                    tickLine={{ stroke: theme.pageText }}
                    tickSize={0}
                  />
                )}
                <Tooltip
                  content={
                    <CustomTooltip
                      balanceTypeOp={balanceTypeOp}
                      thisMonth={thisMonth}
                      lastYear={lastYear}
                      selection={selection}
                    />
                  }
                  formatter={numberFormatterTooltip}
                  isAnimationActive={false}
                />
                <defs>
                  <linearGradient
                    id={`fill${balanceTypeOp}`}
                    x1="0"
                    y1="0"
                    x2="0"
                    y2="1"
                  >
                    <stop
                      offset={gradientOffset()}
                      stopColor={theme.reportsGreen}
                      stopOpacity={0.2}
                    />
                  </linearGradient>
                  <linearGradient
                    id={`stroke${balanceTypeOp}`}
                    x1="0"
                    y1="0"
                    x2="0"
                    y2="1"
                  >
                    <stop
                      offset={gradientOffset()}
                      stopColor={theme.reportsGreen}
                      stopOpacity={1}
                    />
                  </linearGradient>
                </defs>

                <Area
                  type="linear"
                  dot={false}
                  activeDot={{
                    fill: theme.reportsGreen,
                    fillOpacity: 1,
                    r: 10,
                  }}
                  animationDuration={0}
                  dataKey={val => getVal(val, thisMonth)}
                  stroke={`url(#stroke${balanceTypeOp})`}
                  strokeWidth={3}
                  fill={`url(#fill${balanceTypeOp})`}
                  fillOpacity={1}
                />
                <Area
                  type="linear"
                  dot={false}
                  activeDot={false}
                  animationDuration={0}
                  dataKey={val => getVal(val, selection)}
                  stroke="gray"
                  strokeDasharray="10 10"
                  strokeWidth={3}
                  fill="gray"
                  fillOpacity={0.2}
                />
              </AreaChart>
            </div>
          </ResponsiveContainer>
        )
      }
    </Container>
  );
}