import clsx from "clsx";
import { useCallback, useEffect, useRef, useState } from "react";

import styles from "./MultiRangeSlider.module.scss";

export default function MultiRangeSlider({
  min,
  max,
  format,
  currency = "RUB",
  unit = "millimeter",
  defaultMinVal,
  defaultMaxVal,
  onChange,
  className,
}: {
  min: number;
  max: number;
  format?: "currency" | "unit" | undefined;
  currency?: "RUB";
  unit?: "millimeter";
  defaultMinVal?: number;
  defaultMaxVal?: number;
  onChange: (minVal: number, maxVal: number) => void;
  className?: string | undefined;
}) {
  const [minVal, setMinVal] = useState(defaultMinVal ?? min);
  const [maxVal, setMaxVal] = useState(defaultMaxVal ?? max);

  const minValRef = useRef<HTMLInputElement>(null);
  const maxValRef = useRef<HTMLInputElement>(null);
  const rangeRef = useRef<HTMLDivElement>(null);

  const getPercent = useCallback(
    (value: number) => Math.round(((value - min) / (max - min)) * 100),
    [min, max],
  );

  const formatToStyle = (value: number) => {
    if (format === "currency")
      return new Intl.NumberFormat("ru-RU", {
        style: "currency",
        currency: currency,
        minimumFractionDigits: 0,
        maximumFractionDigits: 0,
      }).format(value);

    if (format === "unit")
      return new Intl.NumberFormat("ru-RU", {
        style: "unit",
        unit: unit,
        minimumFractionDigits: 0,
        maximumFractionDigits: 0,
      }).format(value);

    return value.toString();
  };

  useEffect(() => {
    if (maxValRef.current) {
      const minPercent = getPercent(minVal);
      const maxPercent = getPercent(+maxValRef.current.value);

      if (rangeRef.current) {
        rangeRef.current.style.insetInlineStart = `${minPercent.toString()}%`;
        rangeRef.current.style.inlineSize = `${(maxPercent - minPercent).toString()}%`;
      }
    }
  }, [minVal, getPercent]);

  useEffect(() => {
    if (minValRef.current) {
      const minPercent = getPercent(+minValRef.current.value);
      const maxPercent = getPercent(maxVal);

      if (rangeRef.current) {
        rangeRef.current.style.inlineSize = `${(maxPercent - minPercent).toString()}%`;
      }
    }
  }, [maxVal, getPercent]);

  return (
    <div className={clsx(styles["multi-range-slider"], className)}>
      <div className={styles["multi-range-slider__body"]}>
        <input
          type="range"
          min={min}
          max={max}
          ref={minValRef}
          value={minVal}
          onChange={(event) => {
            setMinVal(Math.min(+event.target.value, maxVal - 1));
          }}
          onMouseUp={() => {
            onChange(minVal, maxVal);
          }}
          onTouchEnd={() => {
            onChange(minVal, maxVal);
          }}
          className={clsx(
            styles["multi-range-slider__thumb"],
            styles["multi-range-slider__thumb--z-index--3"],
            minVal > maxVal - 100 &&
              minVal !== min &&
              styles["multi-range-slider__thumb--z-index--5"],
          )}
        />
        <input
          type="range"
          min={min}
          max={max}
          ref={maxValRef}
          value={maxVal}
          onChange={(event) => {
            setMaxVal(Math.max(+event.target.value, minVal + 1));
          }}
          onMouseUp={() => {
            onChange(minVal, maxVal);
          }}
          onTouchEnd={() => {
            onChange(minVal, maxVal);
          }}
          className={clsx(
            styles["multi-range-slider__thumb"],
            styles["multi-range-slider__thumb--z-index--4"],
          )}
        />

        <div className={styles["multi-range-slider__slider"]}>
          <div className={styles["multi-range-slider__track"]}></div>
          <div
            ref={rangeRef}
            className={styles["multi-range-slider__range"]}
          ></div>
        </div>
      </div>

      <div className={styles["multi-range-slider__info-panel"]}>
        <div className={styles["multi-range-slider__min-value"]}>
          {formatToStyle(minVal)}
        </div>

        <div className={styles["multi-range-slider__max-value"]}>
          {formatToStyle(maxVal)}
        </div>
      </div>
    </div>
  );
}
