import {
  createContext,
  ReactNode,
  useContext,
  useEffect,
  useRef,
  useState,
} from "react";
import { IconStateSchema, IconStateType, IconType } from "./types";
import { getAllIcons } from "./utils";

interface IconContextType extends IconStateType {
  setSelectedIcon: (iconName: string | null) => void;
  setSearchQuery: (query: string) => void;
  setActiveCategory: (category: string | null) => void;
  selectedIconObject: IconType | null;

  /**
   * The current color to apply to icons.
   */
  color: string;
  /**
   * Updates the current icon color.
   */
  setColor: (color: string) => void;

  /**
   * current icon size and setter.
   */
  size: number;
  setSize: (size: number) => void;
  hideSizeAndColor: boolean;
}

interface IconPickerProviderProps {
  children: ReactNode;
  /**
   * Initial selected icon name
   */
  defaultValue?: string;
  /**
   * Initial icon color (default: "#000000")
   */
  defaultColor?: string;
  /**
   * Initial icon size (default: "14px")
   */
  defaultSize?: number;
  /**
   * Callback fired when selection changes
   */
  onChange?: (icon: IconType & { color: string; size: number }) => void;
  hideSizeAndColor: boolean;
}

const IconPickerContext = createContext<IconContextType | undefined>(undefined);

export function IconPickerProvider({
  children,
  defaultValue,
  defaultColor,
  defaultSize,
  onChange,
  hideSizeAndColor = false,
}: IconPickerProviderProps) {
  const defaultState = IconStateSchema.parse({
    size: defaultSize,
    color: defaultColor,
    selectedIcon: defaultValue ?? null,
  });

  const [selectedIcon, setSelectedIcon] = useState<string | null>(
    defaultState.selectedIcon,
  );
  const [searchQuery, setSearchQuery] = useState<string>(
    defaultState.searchQuery,
  );
  const [activeCategory, setActiveCategory] = useState<string | null>(
    defaultState.activeCategory,
  );
  const [color, setColor] = useState<string>(defaultState.color);
  const [size, setSize] = useState<number>(defaultState.size);

  const allIcons = getAllIcons();

  const selectedIconObject = selectedIcon
    ? allIcons.find((icon) => icon.name === selectedIcon) || null
    : null;

  // Prevent infinite loops
  const onChangeRef = useRef(onChange);
  useEffect(() => {
    onChangeRef.current = onChange;
  }, [onChange]);

  const initialMountRef = useRef(true);
  useEffect(() => {
    if (initialMountRef.current || !onChangeRef.current || !selectedIconObject)
      return;

    onChangeRef.current({
      ...selectedIconObject,
      color,
      size,
    });
  }, [color, selectedIconObject, size]);

  useEffect(() => {
    initialMountRef.current = false;
  }, []);

  const handleSelectIcon = (iconName: string | null) => {
    setSelectedIcon(iconName);
  };

  return (
    <IconPickerContext.Provider
      value={{
        selectedIcon,
        setSelectedIcon: handleSelectIcon,
        searchQuery,
        setSearchQuery,
        activeCategory,
        setActiveCategory,
        selectedIconObject,
        color,
        setColor,
        size,
        setSize,
        hideSizeAndColor,
      }}
    >
      {children}
    </IconPickerContext.Provider>
  );
}

// eslint-disable-next-line react-refresh/only-export-components
export function useIconPicker() {
  const context = useContext(IconPickerContext);
  if (!context) {
    throw new Error("useIconPicker must be used within an IconPickerProvider");
  }
  return context;
}
