"use client"
import { useEffect, useRef } from "react"

import { createDetailsStore } from "@/stores/enter-details"
import {
  calcTotalMemberPrice,
  calcTotalPublicPrice,
  navigate,
  writeToSessionStorage,
} from "@/stores/enter-details/helpers"

import { bedTypeSchema } from "@/components/HotelReservation/EnterDetails/BedType/schema"
import { breakfastStoreSchema } from "@/components/HotelReservation/EnterDetails/Breakfast/schema"
import {
  guestDetailsSchema,
  signedInDetailsSchema,
} from "@/components/HotelReservation/EnterDetails/Details/schema"
import { DetailsContext } from "@/contexts/Details"

import type { DetailsStore } from "@/types/contexts/enter-details"
import { StepEnum } from "@/types/enums/step"
import type { DetailsProviderProps } from "@/types/providers/enter-details"
import type { DetailsState, InitialState } from "@/types/stores/enter-details"

export default function EnterDetailsProvider({
  bedTypes,
  booking,
  breakfastPackages,
  children,
  packages,
  roomRate,
  searchParamsStr,
  step,
  user,
}: DetailsProviderProps) {
  const storeRef = useRef<DetailsStore>()

  if (!storeRef.current) {
    const initialData: InitialState = { booking, packages, roomRate }
    if (bedTypes.length === 1) {
      initialData.bedType = {
        description: bedTypes[0].description,
        roomTypeCode: bedTypes[0].value,
      }
    }
    if (!breakfastPackages?.length) {
      initialData.breakfast = false
    }

    storeRef.current = createDetailsStore(
      initialData,
      step,
      searchParamsStr,
      user
    )
  }

  useEffect(() => {
    if (storeRef.current) {
      storeRef.current.setState((state) => {
        const newState: DetailsState = { ...state }

        newState.bedType = state.formValues.bedType
        newState.breakfast = state.formValues.breakfast

        if (state.formValues.guest && !user) {
          newState.guest = state.formValues.guest
        }

        if (
          (newState.guest!.join || newState.guest!.membershipNo || user) &&
          state.roomRate.memberRate
        ) {
          const memberPrice = calcTotalMemberPrice(newState)
          newState.roomPrice = memberPrice.roomPrice
          newState.totalPrice = memberPrice.totalPrice
        } else {
          const publicPrice = calcTotalPublicPrice(newState)
          newState.roomPrice = publicPrice.roomPrice
          newState.totalPrice = publicPrice.totalPrice
        }

        const isValid = { ...newState.isValid }

        const validateBooking = state.formValues
        const validPaths = [StepEnum.selectBed]
        const validatedBedType = bedTypeSchema.safeParse(validateBooking)
        if (validatedBedType.success) {
          isValid[StepEnum.selectBed] = true
          validPaths.push(state.steps[1])
        }

        const validatedBreakfast =
          breakfastStoreSchema.safeParse(validateBooking)
        if (validatedBreakfast.success) {
          isValid[StepEnum.breakfast] = true
          validPaths.push(StepEnum.details)
        }

        const detailsSchema = user ? signedInDetailsSchema : guestDetailsSchema
        const validatedDetails = detailsSchema.safeParse(validateBooking.guest)
        /**
         * Need to add the breakfast check here too since
         * when a member comes into the flow, their data is
         * already added and valid, and thus to avoid showing a
         * step the user hasn't been on yet as complete
         */
        if (isValid.breakfast && validatedDetails.success) {
          isValid[StepEnum.details] = true
          validPaths.push(StepEnum.payment)
        }

        if (!validPaths.includes(newState.currentStep!)) {
          newState.currentStep = validPaths.at(-1)!
        }

        if (step !== newState.currentStep) {
          const stateCurrentStep = newState.currentStep!
          setTimeout(() => {
            navigate(stateCurrentStep, searchParamsStr)
          })
        }

        writeToSessionStorage({
          bedType: newState.bedType,
          booking: newState.booking,
          breakfast: newState.breakfast,
          guest: newState.guest,
        })

        return { ...newState, isValid }
      })
    }
  }, [searchParamsStr, step, user])

  return (
    <DetailsContext.Provider value={storeRef.current}>
      {children}
    </DetailsContext.Provider>
  )
}
