"use client"

import { type SyntheticEvent, useMemo, useState } from "react"
import {
  Button,
  ComboBox,
  Input,
  Label,
  ListBox,
  ListBoxItem,
  Popover,
  useFilter,
} from "react-aria-components"
import { useController } from "react-hook-form"
import { useIntl } from "react-intl"

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

import { countries } from "@/constants/countries"

import useLang from "@/hooks/useLang"

import ErrorMessage from "../ErrorMessage"

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

import type { CountryProps } from "./country"

const prioCountryCode = ["DE", "DK", "FI", "NO", "SE"]

export default function CountrySelect({
  // hack used since chrome does not respect autocomplete="off"
  autoComplete = "nope",
  className = "",
  label,
  name = "country",
  readOnly = false,
  registerOptions = {},
}: CountryProps) {
  const lang = useLang()
  const intl = useIntl()

  const { startsWith } = useFilter({ sensitivity: "base" })
  const [filterValue, setFilterValue] = useState("")
  const { field, formState, fieldState } = useController({
    name,
    rules: registerOptions,
  })

  const items = useMemo(() => {
    function mapCountry(country: (typeof countries)[number]) {
      return {
        value: country.code,
        label:
          intl.formatDisplayName(country.code, { type: "region" }) ||
          country.name,
      }
    }

    const collator = new Intl.Collator(lang)
    const prioCountries = countries
      .filter((c) => prioCountryCode.includes(c.code))
      .map(mapCountry)
      .filter((item) => startsWith(item.label, filterValue))
      .sort((a, b) => collator.compare(a.label, b.label))

    const restCountries = countries
      .filter((c) => !prioCountryCode.includes(c.code))
      .map(mapCountry)
      .filter((item) => startsWith(item.label, filterValue))
      .sort((a, b) => collator.compare(a.label, b.label))

    return [...prioCountries, ...restCountries]
  }, [filterValue, intl, lang, startsWith])

  function handleOnInput(evt: SyntheticEvent<HTMLInputElement>) {
    setFilterValue(evt.currentTarget.value)
    const isAutoCompleteEvent = !("inputType" in evt.nativeEvent)
    if (isAutoCompleteEvent) {
      const { value } = evt.currentTarget
      const cc = countries.find((c) => c.name === value || c.code === value)
      if (cc) {
        field.onChange(cc.code)
      }
    }
  }

  return (
    <div className={className}>
      <ComboBox
        aria-label={label}
        className={styles.select}
        data-testid={name}
        isReadOnly={readOnly}
        isRequired={Boolean(registerOptions?.required)}
        isInvalid={fieldState.invalid}
        name={name}
        onBlur={field.onBlur}
        onSelectionChange={(c) => field.onChange(c ?? "")}
        selectedKey={field.value}
        menuTrigger="focus"
      >
        <Label className={styles.inner}>
          <span className={styles.displayText}>
            <Typography variant="Label/xsRegular">
              <span className={`${styles.label} ${styles.labelValue}`}>
                {label}
              </span>
            </Typography>
            <Typography variant="Body/Paragraph/mdRegular">
              <span className={`${styles.label} ${styles.labelEmpty}`}>
                {label}
              </span>
            </Typography>
            <Typography variant="Body/Paragraph/mdRegular">
              <Input
                autoComplete={autoComplete}
                className={styles.input}
                onInput={handleOnInput}
                ref={field.ref}
              />
            </Typography>
          </span>
          <Button className={styles.button}>
            <MaterialIcon
              aria-hidden="true"
              className={styles.chevron}
              color="Icon/Default"
              icon="chevron_right"
              size={24}
            />
          </Button>
        </Label>
        <Popover
          className={styles.popover}
          crossOffset={-8}
          offset={22}
          shouldFlip={false}
        >
          <ListBox className={styles.listBox}>
            {items.map((item) => (
              <ListBoxItem
                className={styles.listBoxItem}
                key={item.value}
                id={item.value}
                textValue={item.label}
              >
                {({ isSelected }) => (
                  <Typography
                    variant={
                      isSelected
                        ? "Body/Paragraph/mdBold"
                        : "Body/Paragraph/mdRegular"
                    }
                  >
                    <span>{item.label}</span>
                  </Typography>
                )}
              </ListBoxItem>
            ))}
          </ListBox>
        </Popover>
      </ComboBox>
      <ErrorMessage errors={formState.errors} name={name} />
    </div>
  )
}
