"use client"
import { useEffect } from "react"
import { useFormContext } from "react-hook-form"
import { useIntl } from "react-intl"
import { useDebounceValue } from "usehooks-ts"

import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"

import { trpc } from "@/lib/trpc/client"

import Divider from "@/components/TempDesignSystem/Divider"
import Body from "@/components/TempDesignSystem/Text/Body"
import Caption from "@/components/TempDesignSystem/Text/Caption"
import Footnote from "@/components/TempDesignSystem/Text/Footnote"
import useLang from "@/hooks/useLang"

import ClearSearchButton from "./ClearSearchButton"
import Dialog from "./Dialog"
import List, { ListSkeleton } from "./List"

import styles from "./searchList.module.css"

import type { SearchListProps } from "@/types/components/search"

export default function SearchList({
  searchInputName,
  getItemProps,
  getMenuProps,
  handleClearSearchHistory,
  highlightedIndex,
  isOpen,
  search,
  searchHistory,
  includeTypes,
}: SearchListProps) {
  const lang = useLang()
  const intl = useIntl()

  const {
    clearErrors,
    formState: { errors, isSubmitted },
  } = useFormContext()
  const searchError = errors[searchInputName]

  const [debouncedSearch, setDebouncedSearch] = useDebounceValue(search, 300)

  useEffect(() => {
    setDebouncedSearch(search)
  }, [search, setDebouncedSearch])

  const autocompleteQueryEnabled = !!debouncedSearch
  const {
    data: autocompleteData,
    isPending,
    isError,
  } = trpc.autocomplete.destinations.useQuery(
    { query: debouncedSearch, lang, includeTypes },
    { enabled: autocompleteQueryEnabled }
  )

  const typeFilteredSearchHistory = searchHistory?.filter((item) => {
    return includeTypes.includes(item.type)
  })

  useEffect(() => {
    clearErrors(searchInputName)
  }, [search, clearErrors, searchInputName])

  useEffect(() => {
    let timeoutID: ReturnType<typeof setTimeout> | null = null
    if (searchError) {
      timeoutID = setTimeout(() => {
        clearErrors(searchInputName)
        // magic number originates from animation
        // 5000ms delay + 120ms exectuion
      }, 5120)
    }

    return () => {
      if (timeoutID) {
        clearTimeout(timeoutID)
      }
    }
  }, [clearErrors, searchError, searchInputName])

  if (searchError && isSubmitted && typeof searchError.message === "string") {
    if (searchError.message === "Required") {
      return (
        <SearchListError
          getMenuProps={getMenuProps}
          caption={intl.formatMessage({
            defaultMessage: "Enter destination or hotel",
          })}
          body={intl.formatMessage({
            defaultMessage:
              "A destination or hotel name is needed to be able to search for a hotel room.",
          })}
        />
      )
    }

    if (searchError.type === "custom") {
      return (
        <SearchListError
          getMenuProps={getMenuProps}
          caption={intl.formatMessage({
            defaultMessage: "No results",
          })}
          body={intl.formatMessage({
            defaultMessage:
              "We couldn't find a matching location for your search.",
          })}
        />
      )
    }
  }

  if (isError) {
    return (
      <SearchListError
        getMenuProps={getMenuProps}
        caption={intl.formatMessage({
          defaultMessage: "Unable to search",
        })}
        body={intl.formatMessage({
          defaultMessage:
            "An error occurred while searching, please try again.",
        })}
      />
    )
  }

  if (!isOpen) {
    return null
  }

  if (
    (autocompleteQueryEnabled && isPending) ||
    (search !== debouncedSearch && search)
  ) {
    return (
      <Dialog getMenuProps={getMenuProps}>
        <ListSkeleton />
      </Dialog>
    )
  }

  const hasAutocompleteItems =
    !!autocompleteData &&
    (autocompleteData.hits.cities.length > 0 ||
      autocompleteData.hits.hotels.length > 0)

  if (!hasAutocompleteItems && debouncedSearch) {
    return (
      <Dialog getMenuProps={getMenuProps} variant="error">
        <Body className={styles.text} textTransform="bold">
          {intl.formatMessage({
            defaultMessage: "No results",
          })}
        </Body>
        <Body className={styles.text} color="uiTextPlaceholder">
          {intl.formatMessage({
            defaultMessage:
              "We couldn't find a matching location for your search.",
          })}
        </Body>
        {typeFilteredSearchHistory && typeFilteredSearchHistory.length > 0 && (
          <>
            <Divider className={styles.noResultsDivider} color="beige" />
            <Footnote
              className={styles.text}
              color="uiTextPlaceholder"
              textTransform="uppercase"
            >
              {intl.formatMessage({
                defaultMessage: "Latest searches",
              })}
            </Footnote>
            <List
              getItemProps={getItemProps}
              highlightedIndex={highlightedIndex}
              locations={typeFilteredSearchHistory}
            />

            <Divider className={styles.divider} color="beige" />
            <ClearSearchButton
              getItemProps={getItemProps}
              handleClearSearchHistory={handleClearSearchHistory}
              highlightedIndex={highlightedIndex}
              index={typeFilteredSearchHistory.length}
            />
          </>
        )}
      </Dialog>
    )
  }

  const displaySearchHistory =
    !debouncedSearch && typeFilteredSearchHistory?.length
  if (displaySearchHistory) {
    return (
      <Dialog getMenuProps={getMenuProps}>
        <Footnote color="uiTextPlaceholder" textTransform="uppercase">
          {intl.formatMessage({
            defaultMessage: "Latest searches",
          })}
        </Footnote>
        <List
          getItemProps={getItemProps}
          highlightedIndex={highlightedIndex}
          locations={typeFilteredSearchHistory}
        />
        <Divider className={styles.divider} color="beige" />
        <ClearSearchButton
          getItemProps={getItemProps}
          handleClearSearchHistory={handleClearSearchHistory}
          highlightedIndex={highlightedIndex}
          index={typeFilteredSearchHistory.length}
        />
      </Dialog>
    )
  }

  if (!search) {
    return null
  }

  return (
    <Dialog getMenuProps={getMenuProps} variant="search">
      <List
        getItemProps={getItemProps}
        highlightedIndex={highlightedIndex}
        label={intl.formatMessage({
          defaultMessage: "Countries",
        })}
        locations={autocompleteData?.hits.countries ?? []}
      />
      <List
        getItemProps={getItemProps}
        highlightedIndex={highlightedIndex}
        initialIndex={autocompleteData?.hits.countries.length ?? 0}
        label={intl.formatMessage({
          defaultMessage: "Cities",
        })}
        locations={autocompleteData?.hits.cities ?? []}
      />
      <List
        getItemProps={getItemProps}
        highlightedIndex={highlightedIndex}
        initialIndex={
          (autocompleteData?.hits.countries.length ?? 0) +
          (autocompleteData?.hits.cities.length ?? 0)
        }
        label={intl.formatMessage({
          defaultMessage: "Hotels",
        })}
        locations={autocompleteData?.hits.hotels ?? []}
      />
    </Dialog>
  )
}

function SearchListError({
  caption,
  body,
  getMenuProps,
}: {
  caption: string
  body: string
  getMenuProps: SearchListProps["getMenuProps"]
}) {
  return (
    <Dialog
      className={`${styles.fadeOut} ${styles.searchError}`}
      getMenuProps={getMenuProps}
      variant="error"
    >
      <Caption className={styles.heading} color="red">
        <MaterialIcon icon="error" color="Icon/Interactive/Accent" />
        {caption}
      </Caption>
      <Body>{body}</Body>
    </Dialog>
  )
}
