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 { resources } from "@lib/resources.ts";
import { getCookie } 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";
import { GenericResource, getNameOfResource } from "@lib/marka/schema.ts";

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

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

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

  // deno-lint-ignore jsx-no-useless-fragment
  return <></>;
}

const SearchResultImage = ({ src }: { src: string }) => {
  return (
    <Image
      class="object-cover w-12 h-12 rounded-full"
      width="50"
      height="50"
      src={src}
      alt="preview image"
    />
  );
};

export const SearchResultItem = (
  { item, showEmoji = false }: {
    item: GenericResource;
    showEmoji?: boolean;
  },
) => {
  const resourceType =
    resources[item.content._type.toLowerCase() as keyof typeof resources];
  const href = item?.path.replace("/resources", "").replace(/\.md$/, "");
  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} />
        : ""}
      {item.image && <SearchResultImage src={item.image?.url} />}
      {getNameOfResource(item)}
    </a>
  );
};

export const SearchResultList = (
  { result, showEmoji }: { result: GenericResource[]; showEmoji?: boolean },
) => {
  return (
    <div class="mt-4">
      {result?.length
        ? (
          <div class="flex flex-col gap-4">
            {result.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?: GenericResource[];
  },
) => {
  const searchQuery = useSignal(q);
  const data = useSignal<GenericResource[] | undefined>(results);
  const isLoading = useSignal(false);
  const showSeenStatus = useSignal(false);
  const inputRef = useRef<HTMLInputElement>(null);

  if ("history" in globalThis) {
    const u = new URL(globalThis.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");
    }

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

  const fetchData = async () => {
    try {
      isLoading.value = true;
      const jsonData = await fetchQueryResource(
        new URL(globalThis?.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 items-52">
        <div
          class="flex items-center gap-1 rounded-2xl 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="seen" checked={showSeenStatus} />
        <Rating rating={4} />
      </header>
      {data.value?.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;
