import { Box, Typography, useTheme } from "@mui/material";
import { useEffect, useState } from "react";
import { useDebouncedCallback } from "use-debounce";

import { CustomSlider } from "@ui_kit/CustomSlider";
import CustomTextField from "@ui_kit/CustomTextField";

import { updateAnswer, useQuizViewStore } from "@stores/quizView/store";

import { sendAnswer } from "@api/quizRelase";
import { enqueueSnackbar } from "notistack";
import type { QuizQuestionNumber } from "../../../model/questionTypes/number";

import { useQuizData } from "@utils/hooks/useQuizData";
import { quizThemes } from "@utils/themes/Publication/themePublication";
import { useQuizId } from "../../../contexts/QuizIdContext";
import { useRootContainerSize } from "../../../contexts/RootContainerWidthContext";

import type { ChangeEvent, SyntheticEvent } from "react";

type NumberProps = {
  currentQuestion: QuizQuestionNumber;
};

export const Number = ({ currentQuestion }: NumberProps) => {
  const qid = useQuizId();
  const { settings } = useQuizData();
  const [inputValue, setInputValue] = useState<string>("0");
  const [minRange, setMinRange] = useState<string>("0");
  const [maxRange, setMaxRange] = useState<string>("100000000000");
  const [reversedInputValue, setReversedInputValue] = useState<string>("0");
  const [reversedMinRange, setReversedMinRange] = useState<string>("0");
  const [reversedMaxRange, setReversedMaxRange] =
    useState<string>("100000000000");
  const theme = useTheme();
  const { answers } = useQuizViewStore();

  const isMobile = useRootContainerSize() < 650;
  const [minBorder, maxBorder] = currentQuestion.content.range
    .split("—")
    .map(window.Number);
  const min = minBorder < maxBorder ? minBorder : maxBorder;
  const max = minBorder < maxBorder ? maxBorder : minBorder;
  const reversed = minBorder > maxBorder;

  const sendAnswerToBackend = async (value: string, noUpdate = false) => {
    try {
      await sendAnswer({
        questionId: currentQuestion.id,
        body: value,
        qid,
      });

      if (!noUpdate) {
        updateAnswer(currentQuestion.id, value, 0);
      }
    } catch (e) {
      enqueueSnackbar("ответ не был засчитан");
    }
  };

  const updateValueDebounced = useDebouncedCallback(async (value: string) => {
    if (reversed) {
      const newValue =
        window.Number(value) < window.Number(min)
          ? String(min)
          : window.Number(value) > window.Number(max)
          ? String(max)
          : value;

      setReversedInputValue(newValue);
      updateAnswer(
        currentQuestion.id,
        String(max + min - window.Number(newValue)),
        0
      );
      await sendAnswerToBackend(String(window.Number(newValue)), true);

      return;
    }

    const newValue =
      window.Number(value) < window.Number(minRange)
        ? minRange
        : window.Number(value) > window.Number(maxRange)
        ? maxRange
        : value;

    setInputValue(newValue);
    await sendAnswerToBackend(newValue);
  }, 1000);
  const updateMinRangeDebounced = useDebouncedCallback(
    async (value: string, crowded = false) => {
      if (reversed) {
        const newMinRange = crowded
          ? window.Number(value.split("—")[1])
          : max + min - window.Number(value.split("—")[0]) < min
          ? min
          : max + min - window.Number(value.split("—")[0]);

        const newMinValue =
          window.Number(value.split("—")[0]) > max
            ? String(max)
            : value.split("—")[0];

        setReversedMinRange(
          crowded ? String(max + min - window.Number(newMinValue)) : newMinValue
        );
        updateAnswer(
          currentQuestion.id,
          `${newMinRange}—${value.split("—")[1]}`,
          0
        );
        await sendAnswerToBackend(
          `${newMinValue}—${value.split("—")[1]}`,
          true
        );

        return;
      }

      const newMinValue = crowded
        ? maxRange
        : window.Number(value.split("—")[0]) < min
        ? String(min)
        : value.split("—")[0];

      setMinRange(newMinValue);
      await sendAnswerToBackend(`${newMinValue}—${value.split("—")[1]}`);
    },
    1000
  );
  const updateMaxRangeDebounced = useDebouncedCallback(
    async (value: string, crowded = false) => {
      if (reversed) {
        const newMaxRange = crowded
          ? window.Number(value.split("—")[1])
          : max + min - window.Number(value.split("—")[1]) > max
          ? max
          : max + min - window.Number(value.split("—")[1]);

        const newMaxValue =
          window.Number(value.split("—")[1]) < min
            ? String(min)
            : value.split("—")[1];

        setReversedMaxRange(
          crowded ? String(max + min - window.Number(newMaxValue)) : newMaxValue
        );
        updateAnswer(
          currentQuestion.id,
          `${value.split("—")[0]}—${newMaxRange}`,
          0
        );
        await sendAnswerToBackend(
          `${value.split("—")[0]}—${newMaxValue}`,
          true
        );

        return;
      }

      const newMaxValue = crowded
        ? minRange
        : window.Number(value.split("—")[1]) > max
        ? String(max)
        : value.split("—")[1];

      setMaxRange(newMaxValue);
      await sendAnswerToBackend(`${value.split("—")[0]}—${newMaxValue}`);
    },
    1000
  );
  const answer = answers.find(
    ({ questionId }) => questionId === currentQuestion.id
  )?.answer as string;

  const sliderValue =
    answer ||
    (reversed
      ? max + min - currentQuestion.content.start + "—" + max
      : currentQuestion.content.start + "—" + max);

  useEffect(() => {
    if (answer) {
      if (answer.includes("—")) {
        if (reversed) {
          setReversedMinRange(
            String(max + min - window.Number(answer.split("—")[0]))
          );
          setReversedMaxRange(
            String(max + min - window.Number(answer.split("—")[1]))
          );
        } else {
          setMinRange(answer.split("—")[0]);
          setMaxRange(answer.split("—")[1]);
        }
      } else {
        if (reversed) {
          setReversedInputValue(String(max + min - window.Number(answer)));
        } else {
          setInputValue(answer);
        }
      }
    }

    if (!answer) {
      setMinRange(String(currentQuestion.content.start));
      setMaxRange(String(max));

      if (currentQuestion.content.chooseRange) {
        setReversedMinRange(String(currentQuestion.content.start));
        setReversedMaxRange(String(min));
      }

      setReversedInputValue(String(currentQuestion.content.start));
      setInputValue(String(currentQuestion.content.start));
    }
  }, []);

  const onSliderChange = (_: Event, value: number | number[]) => {
    const range = Array.isArray(value)
      ? `${value[0]}—${value[1]}`
      : String(value);

    updateAnswer(currentQuestion.id, range, 0);
  };

  const onChangeCommitted = async (
    _: Event | SyntheticEvent<Element, Event>,
    value: number | number[]
  ) => {
    if (currentQuestion.content.chooseRange && Array.isArray(value)) {
      if (reversed) {
        const newMinReversedValue = String(max + min - value[0]);
        const newMaxReversedValue = String(max + min - value[1]);

        setMinRange(String(value[0]));
        setMaxRange(String(value[1]));
        setReversedMinRange(newMinReversedValue);
        setReversedMaxRange(newMaxReversedValue);
        await sendAnswerToBackend(
          `${newMinReversedValue}—${newMaxReversedValue}`,
          true
        );

        return;
      }

      setMinRange(String(value[0]));
      setMaxRange(String(value[1]));
      await sendAnswerToBackend(`${value[0]}—${value[1]}`);

      return;
    }

    if (reversed) {
      setReversedInputValue(String(max + min - window.Number(value)));
    } else {
      setInputValue(String(value));
    }

    await sendAnswerToBackend(String(value));
  };

  const changeValueLabelFormat = (value: number) => {
    if (!reversed) {
      return value;
    }

    const [minSliderBorder, maxSliderBorder] = sliderValue
      .split("—")
      .map(window.Number);

    if (value === minSliderBorder) {
      return max + min - minSliderBorder;
    }

    return max + min - maxSliderBorder;
  };

  const onInputChange = ({ target }: ChangeEvent<HTMLInputElement>) => {
    const value = target.value.replace(/\D/g, "");

    if (reversed) {
      setReversedInputValue(value);
    } else {
      setInputValue(value);
    }

    updateValueDebounced(value);
  };

  const onMinInputChange = ({ target }: ChangeEvent<HTMLInputElement>) => {
    const newValue = target.value.replace(/\D/g, "");

    if (reversed) {
      setReversedMinRange(newValue);

      if (window.Number(newValue) <= window.Number(reversedMaxRange)) {
        const value = max + min - window.Number(reversedMaxRange);
        updateMinRangeDebounced(`${value}—${value}`, true);

        return;
      }

      updateMinRangeDebounced(
        `${newValue}—${max + min - window.Number(reversedMaxRange)}`
      );

      return;
    }

    setMinRange(newValue);

    if (window.Number(newValue) >= window.Number(maxRange)) {
      updateMinRangeDebounced(`${maxRange}—${maxRange}`, true);

      return;
    }

    updateMinRangeDebounced(`${newValue}—${maxRange}`);
  };

  const onMaxInputChange = ({ target }: ChangeEvent<HTMLInputElement>) => {
    const newValue = target.value.replace(/\D/g, "");

    if (reversed) {
      setReversedMaxRange(newValue);

      if (window.Number(newValue) >= window.Number(reversedMinRange)) {
        const value = max + min - window.Number(reversedMinRange);
        updateMaxRangeDebounced(`${value}—${value}`, true);

        return;
      }

      updateMaxRangeDebounced(
        `${max + min - window.Number(reversedMinRange)}—${newValue}`
      );

      return;
    }

    setMaxRange(newValue);

    if (window.Number(newValue) <= window.Number(minRange)) {
      updateMaxRangeDebounced(`${minRange}—${minRange}`, true);

      return;
    }

    updateMaxRangeDebounced(`${minRange}—${newValue}`);
  };

  return (
    <Box>
      <Typography variant="h5" color={theme.palette.text.primary}>
        {currentQuestion.title}
      </Typography>
      <Box
        sx={{
          display: "flex",
          flexDirection: "column",
          width: "100%",
          marginTop: "20px",
          gap: "30px",
          paddingRight: isMobile ? "10px" : undefined,
        }}
      >
        <CustomSlider
          value={
            currentQuestion.content.chooseRange
              ? sliderValue.split("—").length || 0 > 1
                ? sliderValue.split("—").map((item) => window.Number(item))
                : [min, min + 1]
              : window.Number(sliderValue.split("—")[0])
          }
          min={min}
          max={max}
          step={currentQuestion.content.step || 1}
          onChange={onSliderChange}
          onChangeCommitted={onChangeCommitted}
          valueLabelFormat={changeValueLabelFormat}
          sx={{
            color: theme.palette.primary.main,
            "& .MuiSlider-valueLabel": {
              background: theme.palette.primary.main,
            },
          }}
        />

        {!currentQuestion.content.chooseRange && (
          <CustomTextField
            placeholder="0"
            value={reversed ? reversedInputValue : inputValue}
            onChange={onInputChange}
            sx={{
              maxWidth: "80px",
              borderColor: theme.palette.text.primary,
              "& .MuiInputBase-input": {
                textAlign: "center",
                backgroundColor: quizThemes[settings.cfg.theme].isLight
                  ? "white"
                  : theme.palette.background.default,
              },
            }}
          />
        )}

        {currentQuestion.content.chooseRange && (
          <Box
            sx={{
              display: "flex",
              gap: "15px",
              alignItems: "center",
              "& .MuiFormControl-root": { width: "auto" },
            }}
          >
            <CustomTextField
              placeholder="0"
              value={reversed ? String(reversedMinRange) : minRange}
              onChange={onMinInputChange}
              sx={{
                maxWidth: "80px",
                borderColor: theme.palette.text.primary,
                "& .MuiInputBase-input": {
                  textAlign: "center",
                  backgroundColor: quizThemes[settings.cfg.theme].isLight
                    ? "white"
                    : theme.palette.background.default,
                },
              }}
            />
            <Typography color={theme.palette.text.primary}>до</Typography>
            <CustomTextField
              placeholder="0"
              value={reversed ? String(reversedMaxRange) : maxRange}
              onChange={onMaxInputChange}
              sx={{
                maxWidth: "80px",
                borderColor: theme.palette.text.primary,
                "& .MuiInputBase-input": {
                  textAlign: "center",
                  backgroundColor: quizThemes[settings.cfg.theme].isLight
                    ? "white"
                    : theme.palette.background.default,
                },
              }}
            />
          </Box>
        )}
      </Box>
    </Box>
  );
};
