"use client"

import { zodResolver } from "@hookform/resolvers/zod"
import { usePathname, useRouter, useSearchParams } from "next/navigation"
import { useEffect, useState } from "react"
import { FormProvider, useForm } from "react-hook-form"
import { useIntl } from "react-intl"

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

import { PaymentMethodEnum } from "@/constants/booking"
import { guaranteeCallback } from "@/constants/routes/hotelReservation"
import { env } from "@/env/client"
import { trpc } from "@/lib/trpc/client"
import {
  AncillaryStepEnum,
  useAddAncillaryStore,
} from "@/stores/my-stay/add-ancillary-flow"

import Image from "@/components/Image"
import LoadingSpinner from "@/components/LoadingSpinner"
import Modal from "@/components/Modal"
import Divider from "@/components/TempDesignSystem/Divider"
import { toast } from "@/components/TempDesignSystem/Toasts"
import { useGuaranteeBooking } from "@/hooks/booking/useGuaranteeBooking"
import useLang from "@/hooks/useLang"
import { formatPrice } from "@/utils/numberFormatting"

import {
  clearAncillarySessionData,
  generateDeliveryOptions,
  getAncillarySessionData,
  setAncillarySessionData,
} from "../../utils"
import { type AncillaryFormData, ancillaryFormSchema } from "../schema"
import ActionButtons from "./ActionButtons"
import PriceDetails from "./PriceDetails"
import Steps from "./Steps"

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

import type { AddAncillaryFlowModalProps } from "@/types/components/myPages/myStay/ancillaries"
import { BreakfastPackageEnum } from "@/types/enums/breakfast"

export default function AddAncillaryFlowModal({
  booking,
  user,
  savedCreditCards,
  refId,
}: AddAncillaryFlowModalProps) {
  const { currentStep, selectedAncillary, closeModal } = useAddAncillaryStore(
    (state) => ({
      currentStep: state.currentStep,
      selectedAncillary: state.selectedAncillary,
      closeModal: state.closeModal,
    })
  )
  const intl = useIntl()
  const lang = useLang()
  const router = useRouter()
  const searchParams = useSearchParams()
  const pathname = usePathname()

  const [isPriceDetailsOpen, setIsPriceDetailsOpen] = useState(false)
  const guaranteeRedirectUrl = `${env.NEXT_PUBLIC_NODE_ENV === "development" ? `http://localhost:${env.NEXT_PUBLIC_PORT}` : ""}${guaranteeCallback(lang)}`
  const deliveryTimeOptions = generateDeliveryOptions()

  const defaultDeliveryTime = deliveryTimeOptions[0].value

  const formMethods = useForm<AncillaryFormData>({
    defaultValues: {
      quantityWithPoints: null,
      quantityWithCard: user ? null : 1,
      deliveryTime: defaultDeliveryTime,
      optionalText: "",
      termsAndConditions: false,
      paymentMethod: booking.guaranteeInfo
        ? PaymentMethodEnum.card
        : savedCreditCards?.length
          ? savedCreditCards[0].id
          : PaymentMethodEnum.card,
    },
    mode: "onChange",
    reValidateMode: "onChange",
    resolver: zodResolver(ancillaryFormSchema),
  })

  const ancillaryErrorMessage = intl.formatMessage(
    {
      id: "Something went wrong. {ancillary} could not be added to your booking!",
    },
    { ancillary: selectedAncillary?.title }
  )

  function togglePriceDetails() {
    setIsPriceDetailsOpen((isOpen) => !isOpen)
  }

  const utils = trpc.useUtils()
  const addAncillary = trpc.booking.packages.useMutation({
    onSuccess: (data, variables) => {
      if (data) {
        clearAncillarySessionData()
        closeModal()
        utils.booking.confirmation.invalidate({
          confirmationNumber: variables.confirmationNumber,
        })

        toast.success(
          intl.formatMessage(
            { id: "{ancillary} added to your booking!" },
            { ancillary: selectedAncillary?.title }
          )
        )
        router.refresh()
      } else {
        toast.error(ancillaryErrorMessage)
      }
    },
    onError: () => {
      toast.error(ancillaryErrorMessage)
    },
  })

  const { guaranteeBooking, isLoading } = useGuaranteeBooking({
    confirmationNumber: booking.confirmationNumber,
  })

  const onSubmit = (data: AncillaryFormData) => {
    if (!data.termsAndConditions) {
      formMethods.setError("termsAndConditions", {
        message: "You must accept the terms",
      })
      return
    }

    setAncillarySessionData({
      formData: data,
      selectedAncillary,
    })
    if (booking.guaranteeInfo) {
      const packages = []
      if (selectedAncillary?.id && data.quantityWithCard) {
        packages.push({
          code: selectedAncillary.id,
          quantity: data.quantityWithCard,
          comment: data.optionalText || undefined,
        })
      }

      if (selectedAncillary?.loyaltyCode && data.quantityWithPoints) {
        packages.push({
          code: selectedAncillary.loyaltyCode,
          quantity: data.quantityWithPoints,
          comment: data.optionalText || undefined,
        })
      }

      addAncillary.mutate({
        confirmationNumber: booking.confirmationNumber,
        ancillaryComment: data.optionalText,
        ancillaryDeliveryTime: selectedAncillary?.requiresDeliveryTime
          ? data.deliveryTime
          : undefined,
        packages,
        language: lang,
      })
    } else {
      const savedCreditCard = savedCreditCards?.find(
        (card) => card.id === data.paymentMethod
      )
      if (booking.confirmationNumber) {
        const card = savedCreditCard
          ? {
              alias: savedCreditCard.alias,
              expiryDate: savedCreditCard.expirationDate,
              cardType: savedCreditCard.cardType,
            }
          : undefined
        guaranteeBooking.mutate({
          confirmationNumber: booking.confirmationNumber,
          language: lang,
          ...(card && { card }),
          success: `${guaranteeRedirectUrl}?status=success&RefId=${encodeURIComponent(refId)}&ancillary=1`,
          error: `${guaranteeRedirectUrl}?status=error&RefId=${encodeURIComponent(refId)}&ancillary=1`,
          cancel: `${guaranteeRedirectUrl}?status=cancel&RefId=${encodeURIComponent(refId)}&ancillary=1`,
        })
      } else {
        toast.error(
          intl.formatMessage({
            id: "Something went wrong!",
          })
        )
      }
    }
  }

  useEffect(() => {
    const errorCode = searchParams.get("errorCode")
    const ancillary = searchParams.get("ancillary")
    if ((errorCode && ancillary) || errorCode === "AncillaryFailed") {
      const queryParams = new URLSearchParams(searchParams.toString())
      if (ancillary) {
        queryParams.delete("ancillary")
      }
      queryParams.delete("errorCode")
      const savedData = getAncillarySessionData()
      if (savedData?.formData) {
        formMethods.reset(savedData.formData)
      }
      router.replace(`${pathname}?${queryParams.toString()}`)
    }
  }, [searchParams, pathname, formMethods, router])

  if (isLoading) {
    return (
      <div className={styles.loading}>
        <LoadingSpinner />
      </div>
    )
  }

  const modalTitle =
    currentStep === AncillaryStepEnum.selectAncillary
      ? intl.formatMessage({ id: "Upgrade your stay" })
      : selectedAncillary?.title
  return (
    <Modal isOpen={true} onToggle={closeModal} title={modalTitle}>
      <div
        className={`${styles.modalWrapper} ${currentStep === AncillaryStepEnum.selectAncillary ? styles.selectAncillarycontainer : ""}`}
      >
        <FormProvider {...formMethods}>
          <form
            onSubmit={formMethods.handleSubmit(onSubmit)}
            className={styles.form}
            id="add-ancillary-form-id"
          >
            <div className={styles.modalScrollable}>
              {selectedAncillary && (
                <>
                  <div className={styles.imageContainer}>
                    <Image
                      className={styles.image}
                      src={selectedAncillary.imageUrl}
                      alt={selectedAncillary.title}
                      fill
                    />
                  </div>
                  {currentStep !== AncillaryStepEnum.confirmation && (
                    <div className={styles.contentContainer}>
                      <div className={styles.price}>
                        <Typography variant="Body/Paragraph/mdBold">
                          <p>
                            {formatPrice(
                              intl,
                              selectedAncillary.price.totalPrice,
                              selectedAncillary.price.currency
                            )}
                          </p>
                        </Typography>
                        {selectedAncillary.points && (
                          <div className={styles.divider}>
                            <Divider variant="vertical" color="subtle" />
                            <Typography variant="Body/Paragraph/mdBold">
                              <p>
                                {intl.formatMessage(
                                  { id: "{value} points" },
                                  {
                                    value: selectedAncillary.points,
                                  }
                                )}
                              </p>
                            </Typography>
                          </div>
                        )}
                      </div>
                      <div className={styles.description}>
                        {selectedAncillary.description && (
                          <Typography variant="Body/Paragraph/mdRegular">
                            <p
                              dangerouslySetInnerHTML={{
                                __html: selectedAncillary.description,
                              }}
                            ></p>
                          </Typography>
                        )}
                      </div>
                    </div>
                  )}
                </>
              )}
              <Steps user={user} savedCreditCards={savedCreditCards} />
            </div>
          </form>
          {/* TODO: Remove the berakfast check when add breakfast is implemented */}
          {currentStep === AncillaryStepEnum.selectAncillary ||
          selectedAncillary?.id ===
            BreakfastPackageEnum.ANCILLARY_REGULAR_BREAKFAST ? null : (
            <div
              className={
                currentStep === AncillaryStepEnum.confirmation
                  ? styles.confirmStep
                  : styles.actionButtons
              }
            >
              <PriceDetails isPriceDetailsOpen={isPriceDetailsOpen} />
              <ActionButtons
                isPriceDetailsOpen={isPriceDetailsOpen}
                togglePriceDetails={togglePriceDetails}
                isSubmitting={addAncillary.isPending || isLoading}
              />
            </div>
          )}
        </FormProvider>
      </div>
    </Modal>
  )
}
