import { useState, useRef } from "react";
import { AiFillStar, AiOutlineStar } from "react-icons/ai";

import "../../styles/rating-stars.css";

type StarsPropType = {
  totalStars?: number;
  precision?: number;
  color?: string;
};

type MouseType = React.MouseEvent<HTMLDivElement, MouseEvent>;

/**
 *
 * @param props {StarsPropType}
 * @returns a rating component that allows users to hover over the stars to select a rating
 */
export default function HoverableRatingStars(props: StarsPropType) {
  const { totalStars = 5, precision = 0.25, color = "#000" } = props;

  const [activeStar, setActiveStar] = useState<number>(-1);
  const [hoverActiveStar, setHoverActiveStar] = useState<number>(-1);
  const [isHovered, setIsHovered] = useState(false);

  const ratingBoxRef = useRef<HTMLDivElement | null>(null);

  function handleChangeRating(e: MouseType): number {
    const boxRef = ratingBoxRef.current;
    if (!boxRef) return activeStar;

    const { width, left } = boxRef.getBoundingClientRect();
    const percentOfStars = (e.clientX - left) / width;
    const numberOfStars = percentOfStars * totalStars;
    const nearestNumber =
      Math.round((numberOfStars + precision / 2) / precision) * precision;

    return Number(
      nearestNumber.toFixed(precision.toString().split(".")[1]?.length || 0)
    );
  }

  function handleClick(e: MouseType) {
    setIsHovered(false);
    setActiveStar(handleChangeRating(e));
  }

  function handleMouseMove(e: MouseType) {
    setIsHovered(true);
    setHoverActiveStar(handleChangeRating(e));
  }

  function handleMouseLeave(e: MouseType) {
    setHoverActiveStar(-1);
    setIsHovered(false);
  }

  return (
    <div
      className="outer__rating-stars__container"
      onClick={handleClick}
      onMouseMove={handleMouseMove}
      onMouseLeave={handleMouseLeave}
      ref={ratingBoxRef}
    >
      {[...new Array(totalStars)].map((_, index) => {
        const activeState = isHovered ? hoverActiveStar : activeStar;

        const showEmptyIcon = activeState === -1 || activeState < index + 1;

        const isActiveRating = activeState !== 1;
        const isRatingWithPrecision = activeState % 1 !== 0;
        const isRatingEqualToIndex = Math.ceil(activeState) === index + 1;
        const showRatingWithPrecision =
          isActiveRating && isRatingWithPrecision && isRatingEqualToIndex;

        return (
          <div className="inner__rating-stars__container" key={index}>
            <div
              className="filled__star__container"
              style={{
                width: showRatingWithPrecision
                  ? `${(activeState % 1) * 100}%`
                  : "0%",
              }}
            >
              <AiFillStar color={color} />
            </div>

            <div>
              {showEmptyIcon ? (
                <AiOutlineStar color={color} />
              ) : (
                <AiFillStar color={color} />
              )}
            </div>
          </div>
        );
      })}
    </div>
  );
}
