"use client"

import { useCallback, useRef } from "react"
import { useIntl } from "react-intl"

import { useSidePeekScrollToTop } from "@scandic-hotels/common/hooks/useSidePeekScrollToTop"
import { BackToTopButton } from "@scandic-hotels/design-system/BackToTopButton"
import { LoadingSpinner } from "@scandic-hotels/design-system/LoadingSpinner"
import { ShowMoreButton } from "@scandic-hotels/design-system/ShowMoreButton"
import SidePeekSelfControlled from "@scandic-hotels/design-system/SidePeekSelfControlled"
import { Typography } from "@scandic-hotels/design-system/Typography"
import { trpc } from "@scandic-hotels/trpc/client"

import useLang from "@/hooks/useLang"

import { StayCard } from "../../StayCard"
import { groupStaysByYear } from "../../utils/groupStaysByYear"

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

import type { UpcomingStaysNonNullResponseObject } from "@/types/components/myPages/stays/upcoming"

interface UpcomingStaysSidePeekProps {
  isOpen: boolean
  onClose: () => void
}

export function UpcomingStaysSidePeek({
  isOpen,
  onClose,
}: UpcomingStaysSidePeekProps) {
  const intl = useIntl()
  const lang = useLang()
  const shouldFocusNextItem = useRef(false)

  const { scrollContainerRef, showBackToTop, scrollToTop } =
    useSidePeekScrollToTop()

  const { data, isFetching, fetchNextPage, hasNextPage, isLoading } =
    trpc.user.stays.upcoming.useInfiniteQuery(
      {
        limit: 10,
        lang,
        includeFirstStay: true,
      },
      {
        getNextPageParam: (lastPage) => {
          return lastPage?.nextCursor
        },
        enabled: isOpen,
      }
    )

  function loadMoreData() {
    if (hasNextPage) {
      shouldFocusNextItem.current = true
      fetchNextPage()
    }
  }

  const stays = data?.pages
    .filter((page): page is UpcomingStaysNonNullResponseObject => !!page?.data)
    .flatMap((page) => page.data)

  const staysByYear = stays ? groupStaysByYear(stays, "asc") : []

  const lastPage = data?.pages?.[data.pages.length - 1]
  const firstNewTransaction = lastPage?.data?.[0]

  const focusRefCallback = useCallback((node: HTMLAnchorElement | null) => {
    if (!node || !shouldFocusNextItem.current) return
    node.focus()
    shouldFocusNextItem.current = false
  }, [])

  return (
    <SidePeekSelfControlled
      title={intl.formatMessage({
        id: "stays.upcoming.title",
        defaultMessage: "Upcoming stays",
      })}
      isOpen={isOpen}
      onClose={onClose}
      sidePeekSEO={false}
    >
      <div ref={scrollContainerRef} className={styles.content}>
        {isLoading ? (
          <div className={styles.loadingContainer}>
            <LoadingSpinner />
          </div>
        ) : (
          <>
            {staysByYear.map(({ year, stays }) => (
              <section key={year} className={styles.yearSection}>
                <div className={styles.yearHeader}>
                  <Typography variant="Title/Overline/sm">
                    <span className={styles.yearText}>{year}</span>
                  </Typography>
                </div>
                <div className={styles.staysList}>
                  {stays.map((stay) => {
                    const isFirstNewItem = stay === firstNewTransaction
                    return (
                      <StayCard
                        key={stay.attributes.confirmationNumber}
                        stay={stay}
                        ref={isFirstNewItem ? focusRefCallback : null}
                      />
                    )
                  })}
                </div>
              </section>
            ))}
            {hasNextPage && (
              <ShowMoreButton
                isPending={isFetching}
                loadMoreData={loadMoreData}
              />
            )}
          </>
        )}
        {showBackToTop && !isLoading && (
          <BackToTopButton
            label={intl.formatMessage({
              id: "common.backToTop",
              defaultMessage: "Back to top",
            })}
            onPress={scrollToTop}
            position="right"
          />
        )}
      </div>
    </SidePeekSelfControlled>
  )
}
