import { useEffect, useRef } from "preact/hooks";
import useDebouncedCallback from "@lib/hooks/useDebouncedCallback.ts";
import { IconLoader2, IconSearch } from "@components/icons.tsx";
import { useEventListener } from "@lib/hooks/useEventListener.ts";
import { SearchResult } from "@lib/types.ts";
import { resources } from "@lib/resources.ts";
import { getCookie, isLocalImage } from "@lib/string.ts";
import { IS_BROWSER } from "$fresh/runtime.ts";
import Checkbox from "@components/Checkbox.tsx";
import { Rating } from "@components/Rating.tsx";
import { useSignal } from "@preact/signals";
import Image from "@components/Image.tsx";
import { Emoji } from "@components/Emoji.tsx";

export async function fetchQueryResource(url: URL, type = "") {
  const query = url.searchParams.get("q");
  const status = url.searchParams.get("status");

  try {
    url.pathname = "/api/resources";
    url.searchParams.set("q", encodeURIComponent(query || "*"));
    if (status) {
      url.searchParams.set("status", "not-seen");
    }
    if (type) {
      url.searchParams.set("type", type);
    }
    const response = await fetch(url);
    const jsonData = await response.json();
    return jsonData;
  } catch (error) {
    console.error("Error fetching data:", error);
  }
}

export const RedirectSearchHandler = () => {
  if (getCookie("session_cookie")) {
    useEventListener("keydown", (e: KeyboardEvent) => {
      if (e?.target?.nodeName == "INPUT") return;
      if (
        e.key === "?" &&
        window.location.search === ""
      ) {
        window.location.href += "?q=*";
      }
    }, IS_BROWSER ? document?.body : undefined);
  }

  return <></>;
};

const SearchResultImage = ({ src }: { src: string }) => {
  const imageSrc = isLocalImage(src)
    ? `/api/images?image=${src}&width=50&height=50`
    : src;

  return (
    <Image
      class="object-cover w-12 h-12 rounded-full"
      src={imageSrc}
      alt="preview image"
    />
  );
};

export const SearchResultItem = (
  { item, showEmoji = false }: {
    item: NonNullable<SearchResult["hits"]>[number];
    showEmoji?: boolean;
  },
) => {
  const doc = item.document;
  const resourceType = resources[doc.type];
  const href = (resourceType) ? `${resourceType.link}/${doc.id}` : "";
  return (
    <a
      href={href}
      class="p-2 text-white flex gap-4 items-center rounded-2xl hover:bg-gray-700"
    >
      {showEmoji && resourceType
        ? <Emoji class="w-7 h-7" name={resourceType.emoji} />
        : ""}
      {doc?.image && <SearchResultImage src={doc.image} />}
      {doc?.name}
    </a>
  );
};

export const SearchResultList = (
  { result, showEmoji }: { result: SearchResult; showEmoji?: boolean },
) => {
  return (
    <div class="mt-4">
      {result?.hits
        ? (
          <div class="flex flex-col gap-4">
            {result.hits.map((hit) => (
              <SearchResultItem item={hit} showEmoji={showEmoji} />
            ))}
          </div>
        )
        : <div style={{ color: "#818181" }}>No Results</div>}
    </div>
  );
};

const Search = (
  { q = "*", type, results }: {
    q: string;
    type?: string;
    results?: SearchResult;
  },
) => {
  const searchQuery = useSignal(q);
  const data = useSignal<SearchResult | undefined>(results);
  const isLoading = useSignal(false);
  const showSeenStatus = useSignal(false);
  const inputRef = useRef<HTMLInputElement>(null);

  if ("history" in globalThis) {
    const u = new URL(window.location.href);
    if (u.searchParams.get("q") !== searchQuery.value) {
      u.searchParams.set("q", searchQuery.value);
    }
    if (showSeenStatus.value) {
      u.searchParams.set("rating", "0");
    } else {
      u.searchParams.delete("rating");
    }

    window.history.replaceState({}, "", u);
  }

  const fetchData = async () => {
    try {
      isLoading.value = true;
      const jsonData = await fetchQueryResource(
        new URL(window?.location.href),
        type,
      );
      data.value = jsonData;
      isLoading.value = false;
    } catch (error) {
      console.error("Error fetching data:", error);
      isLoading.value = false;
    }
  };
  const debouncedFetchData = useDebouncedCallback(fetchData, 500); // Debounce the fetchData function with a delay of 500ms

  useEffect(() => {
    if (inputRef.current && searchQuery?.value.length === 0) {
      inputRef.current?.focus();
    }
  }, [inputRef.current, searchQuery]);

  const handleInputChange = (event: Event) => {
    const target = event.target as HTMLInputElement;
    if (target.value !== searchQuery.value) {
      searchQuery.value = target.value;
    }
  };

  useEffect(() => {
    debouncedFetchData(); // Call the debounced fetch function with the updated search query
  }, [searchQuery.value, showSeenStatus.value]);

  useEffect(() => {
    debouncedFetchData();
  }, []);

  return (
    <div class="mt-2">
      <header class="flex items-center gap-4">
        <div
          class="flex items-center gap-1 rounded-xl w-full shadow-2xl"
          style={{ background: "#2B2930", color: "#818181" }}
        >
          {isLoading.value && searchQuery.value
            ? <IconLoader2 class="w-4 h-4 ml-4 mr-2 animate-spin" />
            : <IconSearch class="w-4 h-4 ml-4 mr-2" />}
          <input
            type="text"
            style={{ fontSize: "1.2em" }}
            class="bg-transparent py-3 w-full"
            ref={inputRef}
            value={searchQuery.value}
            onInput={handleInputChange}
          />
        </div>
        <Checkbox label="not-seen" checked={showSeenStatus} />
        <Rating rating={4} />
      </header>
      {data?.value?.hits?.length && !isLoading.value
        ? <SearchResultList showEmoji={!type} result={data.value} />
        : isLoading.value
        ? <div />
        : (
          <div
            class="flex items-center gap-2 p-2 my-4 mx-3"
            style={{ color: "#818181" }}
          >
            <Emoji class="w-8 h-8" name="Ghost.png" />
            No Results
          </div>
        )}
    </div>
  );
};

export default Search;
