"use client";
import {
  createContext,
  useContext,
  useMemo,
  useState,
  useTransition,
  type Dispatch,
  type FC,
  type ReactNode,
  type SetStateAction,
} from "react";
import {
  parseAsBoolean,
  parseAsInteger,
  parseAsString,
  parseAsStringLiteral,
  useQueryState,
} from "nuqs";

type RicercaContextType = {
  map: boolean;
  setMap: (
    value: boolean | ((old: boolean) => boolean | null) | null,
  ) => Promise<URLSearchParams>;
  tipo: string;
  setTipo: (
    value: string | ((old: string) => string | null) | null,
  ) => Promise<URLSearchParams>;
  comune: string;
  setComune: (
    value: string | ((old: string) => string | null) | null,
  ) => Promise<URLSearchParams>;
  consegna: number | null;
  setConsegna: (
    value: number | ((old: number | null) => number | null) | null,
  ) => Promise<URLSearchParams>;
  sort: SortTypes;
  setSort: (
    value: SortTypes | ((old: SortTypes) => SortTypes | null) | null,
  ) => Promise<URLSearchParams>;

  comuniOptions: string[];
  tipologieOptions: string[];
  consegnaOptions: number[];
  sortOptions: typeof sortOptions;
  page: number;
  setPage: Dispatch<SetStateAction<number>>;
  lastPageCount: number;
  setlastPageCount: Dispatch<SetStateAction<number>>;
  ResetParams: () => Promise<void>;
  nFiltri: number;
  isLoading: boolean;
};

const sortOptions = ["Recenti", "Prezzo", "Consegna", "Mq", ""] as const;

//sort as string union
export type SortTypes = (typeof sortOptions)[number];

export type AnnunciOptions = {
  comune: string;
  tipo: string;
  consegna: number;
}[];

const RicercaContext = createContext<RicercaContextType | undefined>(undefined);

export const useRicerca = () => {
  const context = useContext(RicercaContext);
  if (!context) {
    throw new Error("useRicerca must be used within a RicercaProvider");
  }
  return context;
};

export const RicercaProvider: FC<{
  children: ReactNode;
  options: AnnunciOptions;
}> = ({ children, options }) => {
  const [isLoading, startTransition] = useTransition();

  const [map, setMap] = useQueryState(
    "map",
    parseAsBoolean.withDefault(false).withOptions({ startTransition }),
  );
  const [tipo, setTipo] = useQueryState(
    "tipo",
    parseAsString.withDefault("").withOptions({ startTransition }),
  );
  const [comune, setComune] = useQueryState(
    "comune",
    parseAsString.withDefault("").withOptions({ startTransition }),
  );
  const [consegna, setConsegna] = useQueryState(
    "consegna",
    parseAsInteger.withOptions({ startTransition }),
  );
  const [sort, setSort] = useQueryState(
    "sort",
    parseAsStringLiteral(sortOptions)
      .withDefault("")
      .withOptions({ startTransition }),
  );

  const [page, setPage] = useState(0);
  const [lastPageCount, setlastPageCount] = useState(100);

  const tipologieOptions = useMemo(() => {
    const set = new Set<string>();
    options.forEach((item) => {
      if (!comune || item.comune === comune) {
        if (!consegna || item.consegna === consegna) {
          set.add(item.tipo);
        }
      }
    });
    return Array.from(set);
  }, [options, comune, consegna]);

  const comuniOptions = useMemo(() => {
    const set = new Set<string>();
    options.forEach((item) => {
      if (!tipo || item.tipo === tipo) {
        if (!consegna || item.consegna === consegna) {
          set.add(item.comune);
        }
      }
    });
    return Array.from(set);
  }, [options, tipo, consegna]);

  const consegnaOptions = useMemo(() => {
    const set = new Set<number>();
    options.forEach((item) => {
      if (!tipo || item.tipo === tipo) {
        if (!comune || item.comune === comune) {
          set.add(item.consegna);
        }
      }
    });
    return Array.from(set);
  }, [options, tipo, comune]);

  const ResetParams = async () => {
    await setTipo("");
    await setComune("");
    await setConsegna(null);
    await setSort("");
    setPage(0);
  };

  const nFiltri =
    [tipo, comune, sort].reduce(
      (count, item) => (item !== "" ? count + 1 : count),
      0,
    ) + (consegna !== null ? 1 : 0);

  return (
    <RicercaContext.Provider
      value={{
        map,
        setMap,
        tipo,
        setTipo,
        comune,
        setComune,
        consegna,
        setConsegna,
        sort,
        setSort,
        comuniOptions,
        tipologieOptions,
        consegnaOptions,
        sortOptions: sortOptions,
        page,
        setPage,

        lastPageCount,
        setlastPageCount,
        ResetParams,
        nFiltri,
        isLoading,
      }}
    >
      {children}
    </RicercaContext.Provider>
  );
};
