import { useCallback, useEffect, useRef, useState } from "react"
import { Dialog, DialogTrigger, Popover } from "react-aria-components"
import { useFormContext } from "react-hook-form"
import { useIntl } from "react-intl"
import { useMediaQuery } from "usehooks-ts"

import { ErrorCircleIcon, InfoCircleIcon } from "@/components/Icons"
import Modal from "@/components/Modal"
import Button from "@/components/TempDesignSystem/Button"
import Checkbox from "@/components/TempDesignSystem/Form/Checkbox"
import Switch from "@/components/TempDesignSystem/Form/Switch"
import Body from "@/components/TempDesignSystem/Text/Body"
import Caption from "@/components/TempDesignSystem/Text/Caption"

import Input from "../Input"
import TabletCodeInput from "./TabletCodeInput"

import styles from "./booking-code.module.css"

import type {
  BookingCodeSchema,
  BookingWidgetSchema,
} from "@/types/components/bookingWidget"

export default function BookingCode() {
  const intl = useIntl()
  const checkIsTablet = useMediaQuery(
    "(min-width: 768px) and (max-width: 1367px)"
  )
  const checkIsDesktop = useMediaQuery("(min-width: 1367px)")
  const [isTablet, setIsTablet] = useState(false)
  const [isDesktop, setIsDesktop] = useState(false)
  const {
    setValue,
    formState: { errors },
    getValues,
    register,
  } = useFormContext<BookingWidgetSchema>()

  const bookingCode: BookingCodeSchema = getValues("bookingCode")
  const [isOpen, setIsOpen] = useState(!!bookingCode?.value)
  const [showRemember, setShowRemember] = useState(false)
  const [showRememberMobile, setShowRememberMobile] = useState(false)
  const codeError = errors["bookingCode"]?.value
  const codeVoucher = intl.formatMessage({ id: "Code / Voucher" })
  const addCode = intl.formatMessage({ id: "Add code" })
  const ref = useRef<HTMLDivElement | null>(null)

  function updateBookingCodeFormValue(value: string) {
    setValue("bookingCode.value", value, { shouldValidate: true })
  }

  function toggleModal(isOpen: boolean) {
    if (!isOpen && !bookingCode?.value) {
      setValue("bookingCode.flag", false)
      setIsOpen(isOpen)
    } else if (!codeError || isOpen) {
      setIsOpen(isOpen)
      if (isOpen || bookingCode?.value) {
        setValue("bookingCode.flag", true)
      }
    }
  }
  const closeIfOutside = useCallback(
    (target: HTMLElement) => {
      if (ref.current && target && !ref.current.contains(target)) {
        setShowRemember(false)
      }
    },
    [setShowRemember, ref]
  )

  function showRememberCheck() {
    setShowRemember(true)
  }

  useEffect(() => {
    setIsTablet(checkIsTablet)
  }, [checkIsTablet])

  useEffect(() => {
    setIsDesktop(checkIsDesktop)
  }, [checkIsDesktop])

  const isRememberMobileVisible =
    !isDesktop && (showRemember || !!bookingCode?.remember)
  useEffect(() => {
    setShowRememberMobile(isRememberMobileVisible)
  }, [isRememberMobileVisible])

  useEffect(() => {
    function handleClickOutside(evt: Event) {
      if (showRemember) {
        const target = evt.target as HTMLElement
        closeIfOutside(target)
      }
    }
    document.body.addEventListener("click", handleClickOutside)
    return () => {
      document.body.removeEventListener("click", handleClickOutside)
    }
  }, [closeIfOutside, showRemember])

  return isTablet ? (
    <div className={styles.container}>
      <DialogTrigger isOpen={isOpen} onOpenChange={toggleModal}>
        <Button type="button" intent="text">
          <Checkbox
            checked={!!bookingCode?.value}
            {...register("bookingCode.flag", {
              onChange: function () {
                if (bookingCode?.value || isOpen) {
                  setValue("bookingCode.flag", true)
                }
              },
            })}
          >
            <Caption color="red" type="bold" asChild>
              <span>{codeVoucher}</span>
            </Caption>
          </Checkbox>
        </Button>
        <Popover
          className={styles.codePopover}
          placement="bottom start"
          offset={36}
        >
          <Dialog>
            {({ close }) => (
              <div className={styles.popover}>
                <TabletCodeInput updateValue={updateBookingCodeFormValue} />
                <div className={styles.bookingCodeRememberVisible}>
                  <CodeRemember
                    bookingCodeValue={bookingCode?.value}
                    onApplyClick={close}
                  />
                </div>
              </div>
            )}
          </Dialog>
        </Popover>
      </DialogTrigger>
      <CodeRulesModal />
    </div>
  ) : (
    <div
      className={styles.container}
      ref={ref}
      onFocus={showRememberCheck}
      onBlur={(e) => closeIfOutside(e.nativeEvent.relatedTarget as HTMLElement)}
    >
      <div className={styles.bookingCodeLabel}>
        <Caption
          color={showRemember ? "uiTextActive" : "red"}
          type="bold"
          asChild
        >
          <span>{codeVoucher}</span>
        </Caption>
        <CodeRulesModal />
      </div>
      <Input
        className="input"
        type="search"
        placeholder={addCode}
        name="bookingCode.value"
        id="booking-code"
        onChange={(event) => updateBookingCodeFormValue(event.target.value)}
        defaultValue={bookingCode?.value}
        autoComplete="off"
      />
      {codeError?.message ? (
        <Caption color="red" className={styles.error}>
          <ErrorCircleIcon color="red" className={styles.errorIcon} />
          {intl.formatMessage({ id: codeError.message })}
        </Caption>
      ) : null}
      {isDesktop ? (
        <div
          className={
            showRemember
              ? styles.bookingCodeRememberVisible
              : styles.bookingCodeRemember
          }
        >
          <CodeRemember
            bookingCodeValue={bookingCode?.value}
            onApplyClick={() => setShowRemember(false)}
          />
        </div>
      ) : (
        <div
          className={
            showRememberMobile
              ? styles.bookingCodeRememberVisible
              : styles.bookingCodeRemember
          }
        >
          <Switch name="bookingCode.remember" className="mobile-switch">
            <Caption asChild>
              <span>{intl.formatMessage({ id: "Remember code" })}</span>
            </Caption>
          </Switch>
        </div>
      )}
    </div>
  )
}

type CodeRememberProps = {
  bookingCodeValue: string | undefined
  onApplyClick: () => void
}

function CodeRulesModal() {
  const intl = useIntl()
  const codeVoucher = intl.formatMessage({ id: "Code / Voucher" })
  const bookingCodeTooltipText = intl.formatMessage({
    id: "If you're booking a promotional offer or a Corporate negotiated rate you'll need a special booking code. Don't use any special characters such as (.) (,) (-) (:). If you would like to make a booking with code VOF, please call us +46 8 517 517 20.Save your booking code for the next time you visit the page by ticking the box “Remember”. Don't tick the box if you're using a public computer to avoid unauthorized access to your booking code.",
  })

  return (
    <Modal
      trigger={
        <Button intent="text">
          <InfoCircleIcon color="uiTextPlaceholder" height={20} width={20} />
        </Button>
      }
      title={codeVoucher}
    >
      <Body color="uiTextHighContrast">{bookingCodeTooltipText}</Body>
    </Modal>
  )
}

function CodeRemember({ bookingCodeValue, onApplyClick }: CodeRememberProps) {
  const intl = useIntl()

  return (
    <>
      <Checkbox name="bookingCode.remember">
        <Caption asChild>
          <span>{intl.formatMessage({ id: "Remember code" })}</span>
        </Caption>
      </Checkbox>
      {bookingCodeValue ? (
        <Button
          size="small"
          className={styles.hideOnMobile}
          intent="secondary"
          type="button"
          onClick={onApplyClick}
        >
          {intl.formatMessage({ id: "Apply" })}
        </Button>
      ) : null}
    </>
  )
}
