import { useQuizStore } from "@/stores/useQuizStore";
import type { QuizQuestionNumber } from "@model/questionTypes/number";
import { Box, Typography, useTheme } from "@mui/material";
import { useQuizViewStore } from "@stores/quizView";
import { CustomSlider } from "@ui_kit/CustomSlider";
import CustomTextField from "@ui_kit/CustomTextField";
import { quizThemes } from "@utils/themes/Publication/themePublication";
import type { ChangeEvent, SyntheticEvent } from "react";
import { useEffect, useState } from "react";
import { useDebouncedCallback } from "use-debounce";

type NumberProps = {
  currentQuestion: QuizQuestionNumber;
};

export const Number = ({ currentQuestion }: NumberProps) => {
  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 { settings } = useQuizStore();
  const { updateAnswer } = useQuizViewStore((state) => state);
  const answers = useQuizViewStore((state) => state.answers);
  const theme = useTheme();

  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 answer = answers.find(({ questionId }) => questionId === currentQuestion.id)?.answer as string;

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

  const sendAnswerToBackend = async (value: string, noUpdate = false) => {
    if (!noUpdate) {
      updateAnswer(currentQuestion.id, value, 0);
    }
  };

  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);

  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));
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  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}
        sx={{ wordBreak: "break-word" }}
      >
        {currentQuestion.title}
      </Typography>
      <Box
        sx={{
          display: "flex",
          flexDirection: "column",
          width: "100%",
          marginTop: "20px",
          gap: "30px",
          padding: "0 30px",
        }}
      >
        <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,
              borderRadius: "8px",
              minWidth: "60px",
              height: "36px",
            },
          }}
        />

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

        {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,
                "& .MuiOutlinedInput-root": { background: "transparent" },
                "& .MuiInputBase-input": { textAlign: "center", zIndex: 1 },
                "& .MuiOutlinedInput-notchedOutline": {
                  backgroundColor: quizThemes[settings.cfg.theme].isLight ? "white" : theme.palette.background.default,
                  borderColor: "#9A9AAF",
                },
              }}
            />
            <Typography color={theme.palette.text.primary}>до</Typography>
            <CustomTextField
              placeholder="0"
              value={reversed ? String(reversedMaxRange) : maxRange}
              onChange={onMaxInputChange}
              sx={{
                maxWidth: "80px",
                "& .MuiOutlinedInput-root": { background: "transparent" },
                "& .MuiInputBase-input": { textAlign: "center", zIndex: 1 },
                "& .MuiOutlinedInput-notchedOutline": {
                  backgroundColor: quizThemes[settings.cfg.theme].isLight ? "white" : theme.palette.background.default,
                  borderColor: "#9A9AAF",
                },
              }}
            />
          </Box>
        )}
      </Box>
    </Box>
  );
};
