import { use, useEffect, useState, type ChangeEvent, type Dispatch, type FormEvent, type SetStateAction } from "react";
import type { SearchFilters } from "../../types/search";
import FilterButton from "../buttons/FilterButton";
import RecipeSearchFilterDropdown from "./RecipeSearchFilterDropdown";
import { SearchRecipes } from "../../services/RecipeService";
import { isApiError } from "../../types/api/error";
import type { Recipe } from "../../types/recipe";
import { useNavigate } from "react-router-dom";
import { FilterContext } from "../../context/FilterContext";
import ROUTE_CONSTANTS from "../../types/routes";

interface RecipeSearchBarProps {
  redirect: boolean;
  searchOnLoad: boolean;
  favorites: boolean;
  setRecipes: Dispatch<SetStateAction<Recipe[]>> | null;

  // Loading is optional
  loading?: boolean;
  setLoading?: Dispatch<SetStateAction<boolean>>;
};

export default function RecipeSearchBar({ redirect, searchOnLoad, favorites, setRecipes, loading, setLoading }: RecipeSearchBarProps) {
  const navigate = useNavigate();
  const { filters, setFilters } = use(FilterContext);

  const [displayDropdown, setDisplayDropdown] = useState<boolean>(false);

  // SERVER FUNCTIONS
  const fetchSearchResults = async () => {
    if (redirect) {
      await navigate(ROUTE_CONSTANTS.Search);
      return;
    }

    // Should not allow many queries, thought we should allow redirect through loading
    if (loading) return;
    if (setLoading) setLoading(true);

    try {
      const result = await SearchRecipes({ ...filters, Favorites: favorites });
      if (isApiError(result)) {
        console.error(result.message);
        return;
      }

      if (setRecipes)
        setRecipes(result);
    } finally {
      if (setLoading) setLoading(false);
    }
  }

  // HANDLERS
  const toggleDropdownHandler = () => setDisplayDropdown(!displayDropdown);

  // TODO: Store filters in a global state somewhere!
  const searchHandler = async (e: FormEvent<HTMLFormElement>): Promise<void> => {
    e.preventDefault();
    await fetchSearchResults();
  };

  const queryInputHandler = (e: ChangeEvent<HTMLInputElement>) => {
    const new_filters: SearchFilters = {
      ...filters,
      Search: e.target.value,
    };
    setFilters(new_filters);
  }

  // EFFECTS
  // TODO: Learn how to use 'useCallback' here to prevent endless loading and fix warning
  useEffect(() => {
    if (searchOnLoad)
      void fetchSearchResults();
  }, [searchOnLoad]);

  return (
    <form className="w-full px-4 my-8" onSubmit={(e) => void searchHandler(e)}>
      <div className="flex w-full gap-x-2">
        <div className="relative w-full">
          <input type="hidden" name="redirect" value={JSON.stringify(redirect)} />
          <input
            type="search"
            name="search"
            placeholder="Search recipes, ingredients..."
            value={filters ? filters.Search : ""}
            onChange={queryInputHandler}
            className="w-full pr-4 pl-10 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
          />
          <button className="absolute left-3 top-1/2 -translate-y-1/2">
            <svg
              className="h-5 w-5 text-gray-400"
              fill="none"
              stroke="currentColor"
              viewBox="0 0 24 24"
              xmlns="http://www.w3.org/2000/svg"
            >
              <path
                strokeLinecap="round"
                strokeLinejoin="round"
                strokeWidth="2"
                d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"
              ></path>
            </svg>
          </button>
        </div>
        <FilterButton click={toggleDropdownHandler} />
      </div>
      <RecipeSearchFilterDropdown filters={filters} setFilters={setFilters} display={displayDropdown} />
    </form>
  );
}
