import React, {useCallback, useEffect, useRef, useState} from "react";
import {
  init,
  dispose,
  Chart,
  IndicatorFigureStylesCallbackData,
  Indicator,
  IndicatorStyle,
  KLineData,
  utils,
  ActionType,
} from "klinecharts";
import {CandleChartProps} from "./CandleChart.props";
import CandleChartToolbar from "./CandleChartToolbar";
import {Box, Button, ButtonGroup, CircularProgress, Icon, IconButton, Stack, useTheme} from "@mui/material";
import getMinutesTickSizeByInterval from "./utils/getMinutesTickSizeByInterval.util";
import drawTrade from "./utils/drawTrade.util";
import drawTradeLines from "./utils/drawTradeLines.util";
import {BasketIcon, ScreenIcon} from "../../icons";
import {FullScreen, useFullScreenHandle} from "react-full-screen";
import dayjs from "dayjs";
import {fetchSymbolsKlines} from "../../../actions/binance";
import {useSnackbar} from "notistack";
import {useSelector} from "react-redux";
import {AppState} from "../../../store/store";
import useComponentResizeListener from "../../../hooks/componentResizeListener";
import {chartStyles} from "./ChartStyles";

interface Vol {
  volume?: number
}

export const CandleChart = ({
  candles,
  uniqueId,
  symbolName,
  orders,
  amount,
  openPrice,
  closePrice,
  onScreenshotCreated,
  chartInterval,
  setChartInterval,
  waiting,
  setWaiting,
  height,
  showIntervalSelector,
}: CandleChartProps) => {
  const chart = useRef<Chart|null>(null);
  const paneId = useRef<string>("");
  const [figureId, setFigureId] = useState<string>("");
  const ref = useRef<HTMLDivElement>(null);
  const handle = useFullScreenHandle();
  const {enqueueSnackbar} = useSnackbar();
  const precision = useSelector((state: AppState) => state.binancePrecision.futures[symbolName.toUpperCase()]);
  const kline = useSelector((state: AppState) => state.binanceKline.futures[`${symbolName.toLocaleLowerCase()}@kline_${chartInterval}`]) || null;
  const size = useComponentResizeListener(ref);
  const theme = useTheme();
  const darkMode = theme.palette.mode === "dark";

  const chartResize = useCallback(() => {
    if (null !== chart.current) {
      chart.current.resize();
    }
  }, [chart.current]);

  useEffect(() => {
    if (precision && null !== chart.current) {
      chart.current.setPriceVolumePrecision(precision?.price || 4, precision?.quantity || 2);
    }
  }, [chart.current, precision]);

  useEffect(() => {
    if (kline && null !== chart.current) {
      chart.current.updateData(kline);
    }
  }, [kline, chart.current]);

  useEffect(() => {
    chartResize();
  }, [size]);

  useEffect(() => {
    // @ts-ignore
    chart.current = init(`chart-${uniqueId}`, {styles: chartStyles(theme)});

    return () => dispose(`chart-${uniqueId}`);
  }, [uniqueId]);

  useEffect(() => {
    if (chart.current) {
      chart.current.setStyles({
        grid: {
          horizontal: {
            color: theme.palette.grey[50],
          },
          vertical: {
            color: theme.palette.grey[50],
          },
        },
        xAxis: {
          axisLine: {
            color: theme.palette.grey[50],
          },
        },
        yAxis: {
          axisLine: {
            color: theme.palette.grey[50],
          },
        },
        separator: {
          color: theme.palette.grey[50],
        },
      });
    }
  }, [theme]);

  useEffect(() => {
    if (null !== chart.current) {
      window.addEventListener("resize", chartResize);
    }

    return () => window.removeEventListener("resize", chartResize);
  }, []);

  useEffect(() => {
    chart.current?.applyNewData(candles);
    chart.current?.overrideIndicator({
      name: "VOL",
      shortName: "Объем",
      calcParams: [],
      figures: [
        {
          key: "volume",
          title: "",
          type: "bar",
          baseValue: 0,
          styles: (data: IndicatorFigureStylesCallbackData<Vol>, indicator: Indicator, defaultStyles: IndicatorStyle) => {
            const kLineData = data.current.kLineData as KLineData;
            let color: string;

            if (kLineData.close > kLineData.open) {
              color = utils.formatValue(indicator.styles, "bars[0].upColor", (defaultStyles.bars)[0].upColor) as string;
            } else if (kLineData.close < kLineData.open) {
              color = utils.formatValue(indicator.styles, "bars[0].downColor", (defaultStyles.bars)[0].downColor) as string;
            } else {
              color = utils.formatValue(indicator.styles, "bars[0].noChangeColor", (defaultStyles.bars)[0].noChangeColor) as string;
            }

            return {color};
          },
        },
      ],
    }, paneId.current);
    chart.current?.createIndicator("VOL", false, {id: paneId.current});
  }, [candles]);

  useEffect(() => {
    if (!orders || orders.length === 0 || candles.length === 0 || !amount || amount.length === 0) return;

    const minTime = orders[0].time;
    const maxTime = orders[orders.length - 1].time;
    const needleTime = minTime + (maxTime - minTime) / 2;

    chart.current?.scrollToTimestamp(needleTime + 50 * getMinutesTickSizeByInterval(chartInterval) * 60 * 1000);
    drawTrade(chart, paneId, orders, chartInterval, amount);

    if (openPrice && closePrice) {
      let openTime = Infinity;
      let closeTime = -Infinity;

      orders.forEach(order => {
        if (openTime > order.time) {
          openTime = order.time;
        }

        if (closeTime < order.time) {
          closeTime = order.time;
        }
      });

      drawTradeLines(
        chart,
        openPrice,
        openTime,
        closePrice,
        closeTime,
        orders[0].position,
        paneId,
        precision.price,
        precision.quantity,
      );
    }
  }, [orders, candles, uniqueId]);

  const removeFigure = () => {
    chart.current?.removeOverlay({
      id: figureId,
    });
    setFigureId("");
  };

  const onButtonClick = async() => {
    const url = chart.current?.getConvertPictureUrl(true);

    if (!url || !onScreenshotCreated) {
      return;
    }

    onScreenshotCreated(url);
  };

  useEffect(() => {
    if (candles.length === 0) return;
    chart.current?.subscribeAction(ActionType.OnScroll, onScrollbarPositionChanged);

    return (() => {
      chart.current?.unsubscribeAction(ActionType.OnScroll, onScrollbarPositionChanged);
    });
  }, [chart.current, candles]);

  let isLoading = false;

  let onScrollbarPositionChanged = () => {
    const chartWidth = chart.current?.getSize()?.width;
    const barSpace = chart.current?.getBarSpace();
    const rightDistance = chart.current?.getOffsetRightDistance();

    const dataList = chart.current?.getDataList();
    const from = chart.current?.getVisibleRange().realFrom;

    if (!dataList || isLoading || !chartWidth || !barSpace) return;

    if (rightDistance) {
      if (0 < rightDistance && rightDistance !== 50) {
        let startTime = dataList[dataList.length - 1].timestamp;

        if (isLastCandleToday(startTime, chartInterval)) return;

        isLoading = true;
        setWaiting(true);
        fetchSymbolsKlines(symbolName, chartInterval, startTime).then((data) => {
          if (undefined === data) return;

          const newCandles = data?.map((item: any[]) => ({
            timestamp: item[0],
            open: item[1],
            high: item[2],
            low: item[3],
            close: item[4],
            volume: item[5],
          }));

          if (!newCandles || newCandles.length === 0) {
            isLoading = false;
            setWaiting(false);

            return;
          } else {
            const newData = [...dataList, ...newCandles];
            chart.current?.applyNewData(newData, true);
            const newRightDistance = (-barSpace * newCandles.length) + rightDistance;
            chart.current?.setOffsetRightDistance(newRightDistance + 140);
          }

          isLoading = false;
          setWaiting(false);
        })
          .catch((error) => {
            enqueueSnackbar(error.message, {variant: "error"});
            isLoading = false;
            setWaiting(false);
          });
      }
    }

    if (from === 0) {
      let endTime = dataList[0].timestamp;
      let prevTime: number | null = null;
      isLoading = true;
      setWaiting(true);

      fetchSymbolsKlines(symbolName, chartInterval, undefined, endTime).then((data) => {
        if (undefined === data) return;

        const newCandles = data?.map((item: any[]) => ({
          timestamp: item[0],
          open: item[1],
          high: item[2],
          low: item[3],
          close: item[4],
          volume: item[5],
        }));

        if (!newCandles || newCandles.length === 0) {
          return;
        } else {
          if (prevTime === newCandles[newCandles.length - 1].timestamp) {
            isLoading = false;
            setWaiting(false);

            return;
          }

          if (newCandles[newCandles.length - 1].timestamp === dataList[dataList.length - 1].timestamp) {
            isLoading = false;
            setWaiting(false);

            return;
          }

          prevTime = newCandles[newCandles.length - 1].timestamp;
          chart.current?.applyMoreData(newCandles);
        }

        isLoading = false;
        setWaiting(false);
      })
        .catch((error) => {
          enqueueSnackbar(error.message, {variant: "error"});
          isLoading = false;
          setWaiting(false);
        });
    }
  };

  const isLastCandleToday = (lastCandleTimestamp: number, interval: string) => {
    const lastCandleDate = dayjs(lastCandleTimestamp);
    const today = dayjs();

    if (interval.includes("m") || interval.includes("h") || interval.includes("d")) {
      return lastCandleDate.isSame(today, "day");
    }

    return false;
  };

  return (<>
    <FullScreen handle={handle}>
      <Box height="100%" sx={{borderRadius: "1rem", position: "relative", background: theme => theme.palette.background.paper}}>
        {
          showIntervalSelector &&
          <Stack sx={{
            padding: "0 5px", width: "100%", height: 40,
            justifyContent: "space-between", flexDirection: "row", borderBottom: theme => `2px solid ${theme.palette.grey[50]}`,
          }}>
            <ButtonGroup>
              {
                ["1m", "3m", "5m", "15m", "30m", "1h", "4h", "12h", "1d"].map(interval => (
                  <Button
                    key={interval}
                    color="inherit"
                    sx={{px: 1, py: .5,
                      color: interval === chartInterval ? darkMode ? "#fff" : "#677294" : "#999999",
                      fontSize: ".75rem", "&:hover": {backgroundColor: darkMode ? "#2b2b2b !important" : ""},
                    }}
                    variant={"text"}
                    onClick={() => setChartInterval && setChartInterval(interval)}
                  >{interval}</Button>
                ))
              }
            </ButtonGroup>
            <IconButton sx={{borderRadius: 2, fontFamily: "Mont", mr: 1, color: darkMode ? "#999" : "#677294", "&:hover": {backgroundColor: darkMode ? "#2b2b2b !important" : ""}}} onClick={onButtonClick}>
              <Icon sx={{width: 90}} component={ScreenIcon} />
            </IconButton>
          </Stack>
        }
        {
          waiting ? (
            <CircularProgress
              style={{position: "absolute", marginLeft: "1rem"}}
              color="inherit"
              size={32}
            />
          ) : (<></>)
        }
        <Stack direction="row" height={height && !handle.active ? 550 : "100%" || "calc(100% - 140px)"} width="100%">
          <CandleChartToolbar
            setFigureId={setFigureId}
            chart={chart}
            paneId={paneId}
            handle={handle}
          />
          <Box
            ref={ref}
            id={`chart-${uniqueId}`}
            width="calc(100% - 55px)"
            height="100%"
            sx={{borderLeft: theme => `2px solid ${theme.palette.grey[50]}`}}
          >
            {
              figureId.length > 0 &&
              <Stack
                sx={{
                  backgroundColor: darkMode ? "#474747" : "#CBD4E3",
                  borderRadius: 1,
                  position: "absolute",
                  zIndex: 10,
                  right: 80,
                  top: 30,
                  border: theme => `2px solid ${theme.palette.grey[50]}`,
                }}
                spacing={2}
              >
                <IconButton sx={{borderRadius: 1}} onClick={removeFigure}>
                  <Icon component={BasketIcon} />
                </IconButton>
              </Stack>
            }
          </Box>
        </Stack>

      </Box>
    </FullScreen>
  </>);
};

CandleChart.displayName = "CandleChart";

import {Icon, IconButton, Stack, useTheme} from "@mui/material";
import {BasketIcon, FullScreenIcon} from "../../icons";
import React from "react";
import {CandleChartToolbarProps} from "./CandleChartToolbar.props";
import RectTool from "./Tools/RectTool";
import FibonacciLineTool from "./Tools/FibonacciLineTool";
import HorizontalStraightLineTool from "./Tools/HorizontalStraightLineTool";
import ParallelStraightLineTool from "./Tools/ParallelStraightLineTool";
import RayLineTool from "./Tools/RayLineTool";
import PriceLineTool from "./Tools/PriceLineTool";
import SegmentTool from "./Tools/SegmentTool";
import StraightLineTool from "./Tools/StraightLineTool";
import RulerTool from "./Tools/RulerTool";

const CandleChartToolbar = ({chart, paneId, setFigureId, handle}: CandleChartToolbarProps) => {
  const darkMode = useTheme().palette.mode === "dark";

  const removeOverlay = () => {
    chart.current?.removeOverlay();
    setFigureId("");
  };

  const fullScreenHandle = () => {
    if(handle.active) {
      handle.exit();
    } else {
      handle.enter();
    }
  };

  return <>
    <Stack
      className="scroll-block"
      direction="column"
      alignItems="center"
      spacing={1}
      sx={{
        width: "55px",
        height: "100%",
        overflowY: "scroll",
        scrollbarWidth: "thin",
        "&::-webkit-scrollbar": {
          width: "8px",
        },
        "&::-webkit-scrollbar-track": {
          background: theme => theme.palette.background.paper,
        },
        "&::-webkit-scrollbar-thumb": {
          backgroundColor: theme => theme.palette.grey[300],
          border: theme => `3px solid ${theme.palette.white.main}`,
        },
      }}
    >
      <PriceLineTool chart={chart} paneId={paneId} setFigureId={setFigureId}/>
      <HorizontalStraightLineTool chart={chart} paneId={paneId} setFigureId={setFigureId}/>
      <RayLineTool chart={chart} paneId={paneId} setFigureId={setFigureId}/>
      <SegmentTool chart={chart} paneId={paneId} setFigureId={setFigureId}/>
      <StraightLineTool chart={chart} paneId={paneId} setFigureId={setFigureId}/>
      <ParallelStraightLineTool chart={chart} paneId={paneId} setFigureId={setFigureId}/>
      <FibonacciLineTool chart={chart} paneId={paneId} setFigureId={setFigureId}/>
      <RulerTool chart={chart} paneId={paneId} setFigureId={setFigureId}/>
      <RectTool chart={chart} paneId={paneId} setFigureId={setFigureId}/>

      <IconButton sx={{borderRadius: 2, "&:hover": {backgroundColor: darkMode ? "#2b2b2b !important" : ""}}} style={{height: 40}} onClick={fullScreenHandle}>
        <Icon component={FullScreenIcon} sx={{height: 18}} />
      </IconButton>

      <IconButton sx={{borderRadius: 2, "&:hover": {backgroundColor: darkMode ? "#2b2b2b !important" : ""}}} onClick={removeOverlay}>
        <Icon component={BasketIcon}/>
      </IconButton>
    </Stack>
  </>;
};

export default CandleChartToolbar;


нужно сделать сохранение того, что ты нарисовал в CandleChartToolbar в  localStorage