import type { ComponentProps, FocusEvent } from 'react'
import type { Banner as BannerType } from '@/models/app'
import { useAtomValue } from 'jotai'
import { useEffect, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { trackEvent } from '@/app/components/base/amplitude'
import { Carousel, useCarousel } from '@/app/components/base/carousel'
import { userProfileAtom } from '@/context/account-state'
import { useLocale } from '@/context/i18n'
import { BannerItem } from './banner-item'
import { IndicatorButton } from './indicator-button'

const AUTOPLAY_DELAY = 5000
const CAROUSEL_OPTIONS = {
  loop: true,
  watchDrag: (_api, event) =>
    !(event.target instanceof Element && event.target.closest('[data-carousel-control]')),
} satisfies NonNullable<ComponentProps<typeof Carousel>['opts']>

type BannerCarouselContentProps = {
  banners: BannerType[]
  accountId?: string
  language: string
}

function BannerCarouselContent({ banners, accountId, language }: BannerCarouselContentProps) {
  const { t } = useTranslation()
  const { api, selectedIndex } = useCarousel()
  const [isPlaying, setIsPlaying] = useState(false)
  const trackedBannerKeysRef = useRef(new Set<string>())
  const shouldResumeAfterFocusRef = useRef(false)
  const nextIndex = (selectedIndex + 1) % banners.length
  const activeBanner = banners[selectedIndex]
  const trackingKey = accountId && activeBanner ? `${accountId}:${activeBanner.id}` : null

  const pauseRotationForFocus = () => {
    const autoplay = api?.plugins().autoplay
    if (!autoplay?.isPlaying()) return

    shouldResumeAfterFocusRef.current = true
    autoplay.stop()
  }

  const resumeRotationAfterFocus = (event: FocusEvent<HTMLDivElement>) => {
    if (event.currentTarget.contains(event.relatedTarget)) return
    if (!shouldResumeAfterFocusRef.current) return

    shouldResumeAfterFocusRef.current = false
    api?.plugins().autoplay?.play()
  }

  const selectBanner = (index: number) => {
    if (!api || index === selectedIndex) return
    api.scrollTo(index)
  }

  useEffect(() => {
    if (!accountId || !activeBanner || !trackingKey) return
    if (trackedBannerKeysRef.current.has(trackingKey)) return

    trackEvent('explore_banner_impression', {
      banner_id: activeBanner.id,
      title: activeBanner.content.title,
      sort: selectedIndex + 1,
      link: activeBanner.link,
      page: 'explore',
      language,
      account_id: accountId,
      event_time: Date.now(),
    })
    trackedBannerKeysRef.current.add(trackingKey)
  }, [accountId, activeBanner, language, selectedIndex, trackingKey])

  useEffect(() => {
    if (!api) return

    const handleAutoplayPlay = () => setIsPlaying(true)
    const handleAutoplayStop = () => setIsPlaying(false)

    // oxlint-disable-next-line eslint-react/set-state-in-effect -- Embla owns this external playback state.
    setIsPlaying(api.plugins().autoplay?.isPlaying() ?? false)
    api.on('autoplay:play', handleAutoplayPlay)
    api.on('autoplay:stop', handleAutoplayStop)

    return () => {
      api.off('autoplay:play', handleAutoplayPlay)
      api.off('autoplay:stop', handleAutoplayStop)
    }
  }, [api])

  const controls =
    banners.length > 1 ? (
      <div
        data-carousel-control
        role="group"
        aria-label={t(($) => $['pagination.pageNumber'], { ns: 'common' })}
        className="pointer-events-auto flex h-7 min-w-0 shrink-0 items-center gap-2 @min-[996px]/banner:max-w-150 @min-[996px]/banner:min-w-60 @min-[996px]/banner:flex-[1_0_0] @min-[996px]/banner:pr-10"
        onFocusCapture={pauseRotationForFocus}
        onBlurCapture={resumeRotationAfterFocus}
      >
        <div className="flex items-center gap-0.5">
          {banners.map((banner, index) => (
            <IndicatorButton
              key={banner.id}
              index={index}
              label={`${String(index + 1).padStart(2, '0')} ${banner.content.title}`}
              isCurrent={index === selectedIndex}
              isNextSlide={index === nextIndex}
              autoplayDelay={AUTOPLAY_DELAY}
              isPaused={!isPlaying}
              onClick={() => selectBanner(index)}
            />
          ))}
        </div>
        <div className="hidden h-px flex-1 bg-divider-regular @min-[1068px]/banner:block" />
      </div>
    ) : null
  const hasFooter = Boolean(activeBanner?.link || controls)

  return (
    <>
      <Carousel.Content aria-live={isPlaying ? 'off' : 'polite'}>
        {banners.map((banner, index) => {
          const isActive = index === selectedIndex

          return (
            <Carousel.Item
              key={banner.id}
              data-banner-id={banner.id}
              aria-label={banner.content.title}
              aria-hidden={!isActive}
              inert={!isActive}
            >
              <BannerItem
                banner={banner}
                sort={index + 1}
                language={language}
                accountId={accountId}
              />
            </Carousel.Item>
          )
        })}
      </Carousel.Content>

      {hasFooter ? (
        <div className="pointer-events-none absolute right-4 bottom-6 left-8 z-40 flex min-w-0 items-center justify-between gap-4 @min-[720px]/banner:right-64 @min-[996px]/banner:right-60 @min-[996px]/banner:flex-wrap @min-[996px]/banner:justify-start @min-[996px]/banner:gap-1">
          {activeBanner?.link ? (
            <div className="flex min-w-0 items-center gap-1.5 py-1 @min-[996px]/banner:max-w-170 @min-[996px]/banner:min-w-120 @min-[996px]/banner:flex-[1_0_0]">
              <span className="flex size-4 items-center justify-center rounded-full bg-text-accent p-0.5">
                <span
                  className="i-ri-arrow-right-line size-3 text-text-primary-on-surface"
                  aria-hidden="true"
                />
              </span>
              <span className="truncate system-sm-semibold-uppercase text-text-accent">
                {t(($) => $['banner.viewMore'], { ns: 'explore' })}
              </span>
            </div>
          ) : null}
          {controls}
        </div>
      ) : null}
    </>
  )
}

type BannerProps = {
  banners: BannerType[]
}

export function Banner({ banners }: BannerProps) {
  const { t } = useTranslation()
  const locale = useLocale()
  const userProfile = useAtomValue(userProfileAtom)
  const enabledBanners = banners.filter((banner) => banner.status === 'enabled')
  const carouselLabel = enabledBanners[0]?.content.category || enabledBanners[0]?.content.title
  const [carouselPlugins] = useState(() => [
    Carousel.Plugin.Fade(),
    Carousel.Plugin.Autoplay({
      delay: AUTOPLAY_DELAY,
      stopOnFocusIn: true,
      stopOnInteraction: false,
      stopOnMouseEnter: true,
      breakpoints: {
        '(prefers-reduced-motion: reduce)': { active: false },
      },
    }),
  ])

  return (
    <div className="relative flex w-full flex-col items-start gap-4 px-8 pt-6 pb-4">
      <div className="flex w-full flex-col gap-1">
        <p className="truncate title-3xl-semi-bold text-text-primary">
          {t(($) => $['banner.greeting'], { name: userProfile.name, ns: 'explore' })}
        </p>
        <p className="truncate body-sm-regular text-text-secondary">
          {t(($) => $['banner.tagline'], { ns: 'explore' })}
        </p>
      </div>

      {enabledBanners.length > 0 ? (
        <Carousel
          opts={CAROUSEL_OPTIONS}
          plugins={carouselPlugins}
          aria-label={carouselLabel}
          className="@container/banner w-full rounded-2xl"
        >
          <BannerCarouselContent
            banners={enabledBanners}
            accountId={userProfile.id}
            language={locale}
          />
        </Carousel>
      ) : null}
    </div>
  )
}
