"use client"
import { useMemo } from "react"
import { useIntl } from "react-intl"

import { Carousel } from "@/components/Carousel"
import Title from "@/components/TempDesignSystem/Text/Title"
import { AddAncillaryProvider } from "@/providers/AddAncillaryProvider"

import AddAncillaryFlowModal from "./AddAncillaryFlow/AddAncillaryFlowModal"
import AncillaryFlowModalWrapper from "./AddAncillaryFlow/AncillaryFlowModalWrapper"
import WrappedAncillaryCard from "./AddAncillaryFlow/WrappedAncillaryCard"
import { AddedAncillaries } from "./AddedAncillaries"
import ViewAllAncillaries from "./ViewAllAncillaries"

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

import type {
  Ancillaries,
  AncillariesProps,
  Ancillary,
  SelectedAncillary,
} from "@/types/components/myPages/myStay/ancillaries"
import { BreakfastPackageEnum } from "@/types/enums/breakfast"
import type { User } from "@/types/user"

function filterPoints(ancillaries: Ancillaries, user: User | null) {
  return ancillaries.map((ancillary) => {
    return {
      ...ancillary,
      ancillaryContent: ancillary.ancillaryContent.map(
        ({ points, ...ancillary }) => ({
          ...ancillary,
          points: user ? points : undefined,
        })
      ),
    }
  })
}

function generateUniqueAncillaries(
  ancillaries: Ancillaries
): Ancillary["ancillaryContent"] {
  const uniqueAncillaries = new Map(
    ancillaries.flatMap((a) => {
      return a.ancillaryContent.map((ancillary) => [ancillary.id, ancillary])
    })
  )
  return [...uniqueAncillaries.values()]
}

/**
 * Adds the breakfast package to the ancillaries
 *
 * Returns the ancillaries array with the breakfast package added to the
 * specified category. If the category doesn't exist it's created.
 */
function addBreakfastPackage(
  ancillaries: Ancillaries,
  breakfast: SelectedAncillary | undefined,
  categoryName: string
): Ancillaries {
  if (!breakfast) return ancillaries

  const category = ancillaries.find((a) => a.categoryName === categoryName)

  if (category) {
    const newCategory = {
      ...category,
      ancillaryContent: [breakfast, ...category.ancillaryContent],
    }

    return ancillaries.map((ancillary) =>
      ancillary.categoryName === categoryName ? newCategory : ancillary
    )
  }

  return [{ categoryName, ancillaryContent: [breakfast] }, ...ancillaries]
}

export function Ancillaries({
  ancillaries,
  booking,
  packages,
  user,
  savedCreditCards,
  refId,
}: AncillariesProps) {
  const intl = useIntl()

  /**
   * A constructed ancillary for breakfast
   *
   * This is a "fake" ancillary for breakfast, since breakfast isn't really an
   * ancillary in the system. This makes it play nicely with the add ancillary
   * flow. If the user shouldn't be able to add breakfast this will be `undefined`.
   */
  const breakfastAncillary = useMemo(() => {
    // This is the logic deciding if breakfast should be addable or not
    if (
      booking.rateDefinition.breakfastIncluded ||
      booking.packages.some((p) =>
        Object.values(BreakfastPackageEnum).includes(
          p.code as unknown as BreakfastPackageEnum
        )
      )
    ) {
      return undefined
    }

    const breakfastPackage = packages?.find(
      (p) => p.code === BreakfastPackageEnum.ANCILLARY_REGULAR_BREAKFAST
    )

    const breakfastAncillary: SelectedAncillary | undefined = breakfastPackage
      ? {
          description: intl.formatMessage({ id: "Buffet" }),
          id: breakfastPackage.code,
          title: intl.formatMessage({ id: "Breakfast" }),
          price: {
            currency: breakfastPackage.localPrice.currency,
            total: breakfastPackage.localPrice.totalPrice,
          },
          // TODO: Change this to the correct URL, whatever that is
          imageUrl:
            "https://images-test.scandichotels.com/publishedmedia/hcf9hchiad7zrvlkc2pt/Breakfast_-_Scandic_Sweden_-_Free_to_use.jpg",
          requiresDeliveryTime: false,
          loyaltyCode: undefined,
          points: undefined,
          hotelId: Number(booking.hotelId),
          categoryName: "Food",
        }
      : undefined

    return breakfastAncillary
  }, [
    booking.packages,
    booking.rateDefinition.breakfastIncluded,
    intl,
    packages,
    booking.hotelId,
  ])

  const allAncillaries = useMemo(() => {
    if (!ancillaries?.length) {
      return []
    }

    const withBreakfastPopular = addBreakfastPackage(
      ancillaries,
      breakfastAncillary,
      "Popular"
    )
    const withBreakfastFood = addBreakfastPackage(
      withBreakfastPopular,
      breakfastAncillary,
      "Food"
    )
    const filtered = filterPoints(withBreakfastFood, user)
    return filtered
  }, [ancillaries, breakfastAncillary, user])

  if (!ancillaries?.length) {
    return null
  }

  const uniqueAncillaries = generateUniqueAncillaries(allAncillaries)

  return (
    <AddAncillaryProvider booking={booking} ancillaries={allAncillaries}>
      <div className={styles.container}>
        <div className={styles.title}>
          <Title as="h5">
            {intl.formatMessage({ id: "Upgrade your stay" })}
          </Title>
          <ViewAllAncillaries />
        </div>

        <div className={styles.ancillaries}>
          {uniqueAncillaries.slice(0, 4).map((ancillary) => (
            <WrappedAncillaryCard ancillary={ancillary} key={ancillary.id} />
          ))}
        </div>

        <div className={styles.mobileAncillaries}>
          <Carousel>
            <Carousel.Content>
              {uniqueAncillaries.map((ancillary) => {
                return (
                  <Carousel.Item key={ancillary.id}>
                    <WrappedAncillaryCard ancillary={ancillary} />
                  </Carousel.Item>
                )
              })}
            </Carousel.Content>
            <Carousel.Previous />
            <Carousel.Next />
            <Carousel.Dots />
          </Carousel>
        </div>

        <AddedAncillaries booking={booking} ancillaries={uniqueAncillaries} />
        <AncillaryFlowModalWrapper>
          <AddAncillaryFlowModal
            user={user}
            booking={booking}
            packages={packages}
            refId={refId}
            savedCreditCards={savedCreditCards}
          />
        </AncillaryFlowModalWrapper>
      </div>
    </AddAncillaryProvider>
  )
}
