import { produce } from "immer"
import { useContext } from "react"
import { create, useStore } from "zustand"

import { clearAncillarySessionData } from "@/components/HotelReservation/MyStay/utils/ancillaries"
import { AddAncillaryContext } from "@/contexts/AddAncillary"

import type {
  Ancillaries,
  Ancillary,
  SelectedAncillary,
} from "@/types/components/myPages/myStay/ancillaries"
import { BreakfastPackageEnum } from "@/types/enums/breakfast"
import type { Room } from "@/types/stores/my-stay"

export enum AncillaryStepEnum {
  selectAncillary = 0,
  selectQuantity = 1,
  selectDelivery = 2,
  confirmation = 3,
}
type Step = {
  step: AncillaryStepEnum
  isValid: boolean
}
type Steps = {
  [AncillaryStepEnum.selectAncillary]?: Step
  [AncillaryStepEnum.selectQuantity]: Step
  [AncillaryStepEnum.selectDelivery]: Step
  [AncillaryStepEnum.confirmation]: Step
}

export type BreakfastData = {
  nrOfAdults: number
  nrOfPayingChildren: number
  nrOfFreeChildren: number
  nrOfNights: number
  priceAdult: number
  priceChild: number
  currency: string
}

export interface AddAncillaryState {
  currentStep: number
  steps: Steps
  booking: Room
  ancillaries: Ancillaries
  categories: Ancillary["categoryName"][]
  selectedCategory: string
  selectCategory: (category: string) => void
  ancillariesBySelectedCategory: Ancillary["ancillaryContent"]
  openModal: () => void
  closeModal: () => void
  prevStep: () => void
  prevStepMobile: () => void
  breakfastData: BreakfastData | null
  setBreakfastData: (breakfastData: BreakfastData | null) => void
  isBreakfast: boolean
  isOpen: boolean
  selectedAncillary: SelectedAncillary | null
  selectAncillary: (ancillary: SelectedAncillary) => void
  selectQuantity: () => void
  selectDeliveryTime: () => void
  selectQuantityAndDeliveryTime: () => void
}

function findAncillaryByCategory(
  ancillaries: Ancillaries,
  selectedCategory: string
) {
  return (
    ancillaries.find((ancillary) => ancillary.categoryName === selectedCategory)
      ?.ancillaryContent ?? []
  )
}

export const createAddAncillaryStore = (
  booking: Room,
  ancillaries: Ancillaries
) => {
  const selectedCategory = ancillaries[0].categoryName
  const ancillariesBySelectedCategory = findAncillaryByCategory(
    ancillaries,
    selectedCategory
  )
  const categories = ancillaries.map((ancillary) => ancillary.categoryName)
  const steps = {
    [AncillaryStepEnum.selectAncillary]: {
      step: AncillaryStepEnum.selectAncillary,
      isValid: true,
    },
    [AncillaryStepEnum.selectQuantity]: {
      step: AncillaryStepEnum.selectQuantity,
      isValid: false,
    },
    [AncillaryStepEnum.selectDelivery]: {
      step: AncillaryStepEnum.selectDelivery,
      isValid: false,
    },
    [AncillaryStepEnum.confirmation]: {
      step: AncillaryStepEnum.confirmation,
      isValid: false,
    },
  }
  return create<AddAncillaryState>((set) => ({
    booking,
    ancillaries,
    categories,
    selectedCategory,
    ancillariesBySelectedCategory,
    currentStep: AncillaryStepEnum.selectAncillary,
    selectedAncillary: null,
    breakfastData: null,
    isBreakfast: false,
    isOpen: false,
    steps,
    openModal: () =>
      set(
        produce((state: AddAncillaryState) => {
          state.isOpen = true
          state.currentStep = AncillaryStepEnum.selectAncillary
        })
      ),
    closeModal: () =>
      set(
        produce((state: AddAncillaryState) => {
          state.isOpen = false
          clearAncillarySessionData()
          state.selectedAncillary = null
          state.steps = steps
        })
      ),
    selectCategory: (category) =>
      set(
        produce((state: AddAncillaryState) => {
          state.selectedCategory = category
          state.ancillariesBySelectedCategory = findAncillaryByCategory(
            state.ancillaries,
            category
          )
        })
      ),
    selectQuantity: () =>
      set(
        produce((state: AddAncillaryState) => {
          if (state.selectedAncillary?.requiresDeliveryTime) {
            state.currentStep = AncillaryStepEnum.selectDelivery
          } else {
            state.steps[AncillaryStepEnum.selectDelivery].isValid = true
            state.currentStep = AncillaryStepEnum.confirmation
          }
          state.steps[AncillaryStepEnum.selectQuantity].isValid = true
        })
      ),
    selectQuantityAndDeliveryTime: () =>
      set(
        produce((state: AddAncillaryState) => {
          state.steps[AncillaryStepEnum.selectQuantity].isValid = true
          state.steps[AncillaryStepEnum.selectDelivery].isValid = true
          state.currentStep = AncillaryStepEnum.confirmation
        })
      ),
    selectDeliveryTime: () =>
      set(
        produce((state: AddAncillaryState) => {
          state.steps[AncillaryStepEnum.selectDelivery].isValid = true
          state.currentStep = AncillaryStepEnum.confirmation
        })
      ),

    prevStep: () =>
      set(
        produce((state: AddAncillaryState) => {
          if (
            state.currentStep === AncillaryStepEnum.selectAncillary ||
            (state.currentStep === AncillaryStepEnum.selectQuantity &&
              !state.steps[AncillaryStepEnum.selectAncillary])
          ) {
            state.isOpen = false
            clearAncillarySessionData()
            state.selectedAncillary = null
            state.steps = steps
          } else {
            if (
              !state.selectedAncillary?.requiresDeliveryTime &&
              state.currentStep === AncillaryStepEnum.confirmation
            ) {
              state.currentStep = AncillaryStepEnum.selectQuantity
            } else if (state.currentStep === AncillaryStepEnum.selectQuantity) {
              state.currentStep = state.currentStep - 1
              state.selectedAncillary = null
            } else {
              state.currentStep = state.currentStep - 1
            }
          }
        })
      ),
    prevStepMobile: () =>
      set(
        produce((state: AddAncillaryState) => {
          if (state.currentStep === AncillaryStepEnum.selectQuantity) {
            state.isOpen = false
            clearAncillarySessionData()
            state.selectedAncillary = null
            state.steps = steps
          } else {
            if (state.currentStep === AncillaryStepEnum.confirmation) {
              state.currentStep = AncillaryStepEnum.selectQuantity
            } else {
              state.currentStep = state.currentStep - 1
            }
          }
        })
      ),
    selectAncillary: (ancillary) =>
      set(
        produce((state: AddAncillaryState) => {
          if (state.isOpen) {
            state.steps[AncillaryStepEnum.selectAncillary]!.isValid = true
          } else {
            state.isOpen = true
            delete state.steps[AncillaryStepEnum.selectAncillary]
          }
          state.selectedAncillary = ancillary
          state.currentStep = AncillaryStepEnum.selectQuantity
          state.isBreakfast =
            ancillary.id === BreakfastPackageEnum.ANCILLARY_REGULAR_BREAKFAST
        })
      ),
    setBreakfastData: (breakfastData) =>
      set(
        produce((state: AddAncillaryState) => {
          state.breakfastData = breakfastData
        })
      ),
  }))
}
export const useAddAncillaryStore = <T>(
  selector: (state: AddAncillaryState) => T
) => {
  const store = useContext(AddAncillaryContext)
  if (!store) {
    throw new Error(
      "useAddAncillaryStore must be used within AddAncillaryProvider"
    )
  }
  return useStore(store, selector)
}
