'use client'

import Image from 'next/image'
import { useEffect, useMemo, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { FiCheck, FiChevronLeft, FiChevronRight, FiMinus, FiPlay, FiPlus, FiX } from 'react-icons/fi'
import { GIFT_SEND_COUNT_MAX, clampGiftSendCount } from '@/lib/gifts/wsGift'
import { fetchStickerCatalog, formatCategoryTabLabel, isLottieJsonUrl, STICKER_PAGE_SIZE } from '@/lib/stickers/catalog'
import type { StickerCatalog, StickerItem } from '@/lib/stickers/types'
import { formatGiftRecipientPublicId, type GiftRecipient } from '@/app/room/_components/types'

const GIFT_CELL_CLASS = 'aspect-square w-full min-h-0 box-border'
const GIFT_PAGINATION_HEIGHT_CLASS = 'h-10'
const GIFT_GRID_AREA_CLASS = 'w-full shrink-0'
const GIFT_CONTENT_HEIGHT_CLASS = 'h-[24.5rem]'
const GIFT_COIN_IMAGE = '/images/room/coin.png'
const GIFT_MODAL_SUMMARY_COIN_ICON_CLASS = 'w-5 h-5'
const GIFT_MODAL_SUMMARY_COIN_ICON_PX = 20

function parseGiftCountInput(raw: string): number {
    const digits = raw.replace(/[^\d]/g, '')
    if (!digits) return 0
    const n = Number(digits)
    if (!Number.isFinite(n)) return 0
    return clampGiftSendCount(n)
}

function CoinIcon({ className, size = 16 }: { className?: string; size?: number }) {
    return (
        <Image
            src={GIFT_COIN_IMAGE}
            alt=""
            width={size}
            height={size}
            className={`shrink-0 object-contain ${className ?? ''}`}
            unoptimized
            aria-hidden
        />
    )
}

function formatCoinAmount(value: number): string {
    return value.toLocaleString()
}

function CoinAmount({
    amount,
    iconClassName = GIFT_MODAL_SUMMARY_COIN_ICON_CLASS,
    valueClassName = 'text-base font-semibold tabular-nums text-gray-900 dark:text-gray-100',
}: {
    amount: number
    iconClassName?: string
    valueClassName?: string
}) {
    return (
        <span className="inline-flex items-center gap-1.5 min-w-0">
            <CoinIcon className={iconClassName} size={GIFT_MODAL_SUMMARY_COIN_ICON_PX} />
            <span className={valueClassName}>{formatCoinAmount(amount)}</span>
        </span>
    )
}

function showPlayBadge(sticker: StickerItem): boolean {
    return isLottieJsonUrl(sticker.lottieUrl)
}

function GiftGridItem({
    sticker,
    selected,
    onSelect,
}: {
    sticker: StickerItem
    selected: boolean
    onSelect: () => void
}) {
    return (
        <button
            type="button"
            onClick={onSelect}
            aria-label={sticker.name}
            aria-pressed={selected}
            className={`relative flex flex-col items-center justify-center rounded-lg p-1 border-2 transition-colors ${GIFT_CELL_CLASS} ${
                selected ? 'border-gray-900 dark:border-white' : 'border-transparent'
            }`}
        >
            <span
                className={`absolute top-1.5 left-1.5 z-10 w-5 h-5 rounded-full bg-gray-900 dark:bg-white flex items-center justify-center shadow-sm transition-opacity ${selected ? 'opacity-100' : 'opacity-0 pointer-events-none'
                    }`}
                aria-hidden={!selected}
            >
                <FiCheck className="w-3 h-3 text-white dark:text-gray-900" strokeWidth={3} />
            </span>

            <div className="relative flex min-h-0 w-full flex-1 items-center justify-center">
                {sticker.image ? (
                    <Image
                        src={sticker.image}
                        alt=""
                        width={88}
                        height={62}
                        className="max-h-[58px] max-w-[calc(100%-4px)] h-auto w-auto object-contain"
                        unoptimized
                        sizes="120px"
                    />
                ) : (
                    <div className="h-[58px] w-[58px]" aria-hidden />
                )}

                {showPlayBadge(sticker) ? (
                    <span className="absolute top-0.5 right-0.5 w-5 h-5 rounded-md bg-black/80 flex items-center justify-center">
                        <FiPlay className="w-2.5 h-2.5 text-white ml-0.5" fill="currentColor" />
                    </span>
                ) : null}

            </div>

            <div className="mt-0.5 flex shrink-0 items-center justify-center gap-1 h-[18px]">
                <CoinIcon className="w-3.5 h-3.5 shrink-0" />
                <span className="text-xs text-gray-500 dark:text-gray-400 tabular-nums">{sticker.price}</span>
            </div>
        </button>
    )
}

export default function GiftModal({
    giftRef,
    giftClosing,
    giftEntering,
    closeGift,
    giftSelected,
    setGiftSelected,
    giftRecipient,
    streamFallback,
    giftCount,
    setGiftCount,
    onSendGift,
    giftSending = false,
    coinBalance = null,
    coinBalanceLoading = false,
}: {
    giftRef: React.RefObject<HTMLDivElement>
    giftClosing: boolean
    giftEntering: boolean
    closeGift: () => void
    giftSelected: string | null
    setGiftSelected: (id: string | null) => void
    giftRecipient: GiftRecipient | null
    streamFallback: Pick<GiftRecipient, 'userId' | 'displayId' | 'profileApiKey'> & { channelName: string }
    giftCount: number
    setGiftCount: React.Dispatch<React.SetStateAction<number>>
    onSendGift?: () => void
    giftSending?: boolean
    /** 使用者目前 coin 餘額；`null` 表示尚無資料（例如未登入） */
    coinBalance?: number | null
    coinBalanceLoading?: boolean
}) {
    const { t } = useTranslation('translation', { keyPrefix: 'room.giftModal' })
    const [catalog, setCatalog] = useState<StickerCatalog | null>(null)
    const [catalogLoading, setCatalogLoading] = useState(true)
    const [catalogError, setCatalogError] = useState(false)
    const [giftTab, setGiftTab] = useState<string>('basic')
    const [page, setPage] = useState(1)
    const tabsScrollRef = useRef<HTMLDivElement>(null)
    const giftGridRef = useRef<HTMLDivElement>(null)

    useEffect(() => {
        let cancelled = false
        setCatalogLoading(true)
        setCatalogError(false)

        fetchStickerCatalog()
            .then((data) => {
                if (cancelled) return
                setCatalog(data)
                const firstWithItems = data.tabs.find((tab) => tab.stickers.length > 0)
                setGiftTab(firstWithItems?.kind ?? 'basic')
            })
            .catch(() => {
                if (!cancelled) setCatalogError(true)
            })
            .finally(() => {
                if (!cancelled) setCatalogLoading(false)
            })

        return () => {
            cancelled = true
        }
    }, [])

    const activeTabStickers = useMemo(() => {
        if (!catalog) return []
        return catalog.tabs.find((tab) => tab.kind === giftTab)?.stickers ?? []
    }, [catalog, giftTab])

    const totalPages = Math.max(1, Math.ceil(activeTabStickers.length / STICKER_PAGE_SIZE))

    const pageStickers = useMemo(() => {
        const start = (page - 1) * STICKER_PAGE_SIZE
        return activeTabStickers.slice(start, start + STICKER_PAGE_SIZE)
    }, [activeTabStickers, page])

    /** 每頁固定 12 格，不足補空白格避免高度抖動 */
    const pageGridSlots = useMemo(() => {
        const slots: (StickerItem | null)[] = [...pageStickers]
        while (slots.length < STICKER_PAGE_SIZE) {
            slots.push(null)
        }
        return slots
    }, [pageStickers])

    useEffect(() => {
        setPage(1)
    }, [giftTab])

    useEffect(() => {
        if (page > totalPages) {
            setPage(totalPages)
        }
    }, [page, totalPages])

    useEffect(() => {
        if (!giftSelected || !catalog) return
        const selected = catalog.stickerByName.get(giftSelected)
        if (!selected || selected.category !== giftTab) {
            setGiftSelected(null)
        }
    }, [giftTab, giftSelected, catalog, setGiftSelected])

    const selectedSticker: StickerItem | null =
        giftSelected && catalog ? catalog.stickerByName.get(giftSelected) ?? null : null

    const totalPrice = (selectedSticker?.price ?? 0) * giftCount
    const insufficientBalance =
        typeof coinBalance === 'number' && giftCount > 0 && totalPrice > coinBalance

    const balanceDisplay = useMemo(() => {
        if (coinBalanceLoading || typeof coinBalance !== 'number') return t('balanceUnavailable')
        return formatCoinAmount(coinBalance)
    }, [coinBalance, coinBalanceLoading, t])

    const recipientPublicId = useMemo(() => {
        if (giftRecipient) return formatGiftRecipientPublicId(giftRecipient)
        return formatGiftRecipientPublicId({
            userId: streamFallback.userId,
            displayId: streamFallback.displayId,
            profileApiKey: streamFallback.profileApiKey,
        })
    }, [giftRecipient, streamFallback])

    const scrollTabsLeft = () => {
        tabsScrollRef.current?.scrollBy({ left: -120, behavior: 'smooth' })
    }

    const scrollTabsRight = () => {
        tabsScrollRef.current?.scrollBy({ left: 120, behavior: 'smooth' })
    }

    return (
        <div
            className={`fixed inset-0 z-[200] flex items-center justify-center p-3 transition-[opacity] duration-200 ease-[cubic-bezier(0.56,0.12,0.12,0.98)] ${giftClosing || giftEntering ? 'opacity-0 pointer-events-none' : 'opacity-100'
                }`}
        >
            <div className="absolute inset-0 bg-black/60" />

            <div
                ref={giftRef}
                className={`relative w-[502px] max-w-[calc(100vw-24px)] max-h-[90vh] shrink-0 rounded-xl border border-gray-200 dark:border-gray-800 bg-white dark:bg-[#0c0d0e] shadow-2xl overflow-hidden flex flex-col transform-gpu transition-[opacity,transform] duration-200 ease-[cubic-bezier(0.56,0.12,0.12,0.98)] ${giftClosing || giftEntering ? 'opacity-0 scale-95' : 'opacity-100 scale-100'
                    }`}
            >
                <div className="flex items-center px-6 py-3">
                    <div className="text-lg font-semibold text-gray-900 dark:text-white">{t('title')}</div>
                    <button
                        type="button"
                        onClick={() => closeGift()}
                        className="ml-auto w-9 h-9 rounded-full inline-flex items-center justify-center hover:bg-gray-100 dark:hover:bg-[#1a1c21] transition-colors"
                        aria-label={t('close')}
                    >
                        <FiX className="w-5 h-5 text-[#525661] dark:text-gray-200" />
                    </button>
                </div>

                <div className="px-4 flex items-center gap-1 min-w-0">
                    <button
                        type="button"
                        onClick={scrollTabsLeft}
                        className="shrink-0 w-8 h-8 rounded-full flex items-center justify-center text-gray-500 hover:bg-gray-100 dark:hover:bg-[#1a1c21] transition-colors"
                        aria-label={t('prevPage')}
                    >
                        <FiChevronLeft className="w-5 h-5" />
                    </button>
                    <div
                        ref={tabsScrollRef}
                        className="flex-1 min-w-0 flex items-center gap-2 overflow-x-auto hide-scrollbar scroll-smooth"
                    >
                        {(catalog?.tabs ?? []).map((tab) => {
                            const active = giftTab === tab.kind
                            return (
                                <button
                                    key={tab.kind}
                                    type="button"
                                    onClick={() => setGiftTab(tab.kind)}
                                    className={`shrink-0 h-9 px-4 rounded-full text-sm font-medium transition-colors ${active
                                        ? 'bg-gray-900 text-white dark:bg-gray-100 dark:text-gray-900'
                                        : 'bg-gray-100 text-gray-600 hover:bg-gray-200 dark:bg-[#1a1c21] dark:text-gray-300 dark:hover:bg-[#252830]'
                                        }`}
                                >
                                    {formatCategoryTabLabel(tab.kind, t)}
                                </button>
                            )
                        })}
                    </div>
                    <button
                        type="button"
                        onClick={scrollTabsRight}
                        className="shrink-0 w-8 h-8 rounded-full flex items-center justify-center text-gray-500 hover:bg-gray-100 dark:hover:bg-[#1a1c21] transition-colors"
                        aria-label={t('nextPage')}
                    >
                        <FiChevronRight className="w-5 h-5" />
                    </button>
                </div>

                <div className="px-4 pt-3 pb-1 shrink-0">
                    {catalogLoading ? (
                        <div className={`${GIFT_CONTENT_HEIGHT_CLASS} flex items-center justify-center text-sm text-gray-500 dark:text-gray-400`}>
                            {t('loading')}
                        </div>
                    ) : catalogError || !catalog ? (
                        <div className={`${GIFT_CONTENT_HEIGHT_CLASS} flex items-center justify-center text-sm text-gray-500 dark:text-gray-400`}>
                            {t('loadError')}
                        </div>
                    ) : activeTabStickers.length === 0 ? (
                        <div className={`${GIFT_CONTENT_HEIGHT_CLASS} flex items-center justify-center text-sm text-gray-500 dark:text-gray-400`}>
                            {t('empty')}
                        </div>
                    ) : (
                        <>
                            <div ref={giftGridRef} className={`${GIFT_GRID_AREA_CLASS} overflow-hidden`}>
                                <div className="grid w-full grid-cols-4 gap-1">
                                    {pageGridSlots.map((sticker, index) =>
                                        sticker ? (
                                            <GiftGridItem
                                                key={sticker.name}
                                                sticker={sticker}
                                                selected={giftSelected === sticker.name}
                                                onSelect={() => setGiftSelected(sticker.name)}
                                            />
                                        ) : (
                                            <div
                                                key={`gift-slot-empty-${index}`}
                                                className={`${GIFT_CELL_CLASS} border-2 border-transparent`}
                                                aria-hidden
                                            />
                                        ),
                                    )}
                                </div>
                            </div>

                            <div
                                className={`${GIFT_PAGINATION_HEIGHT_CLASS} shrink-0 flex items-center justify-center gap-3`}
                            >
                                {totalPages > 1 ? (
                                    <>
                                        <button
                                            type="button"
                                            disabled={page <= 1}
                                            onClick={() => setPage((p) => Math.max(1, p - 1))}
                                            className="w-8 h-8 rounded-full inline-flex items-center justify-center hover:bg-gray-100 dark:hover:bg-[#1a1c21] disabled:opacity-40 disabled:pointer-events-none transition-colors"
                                            aria-label={t('prevPage')}
                                        >
                                            <FiChevronLeft className="w-5 h-5 text-[#525661] dark:text-gray-200" />
                                        </button>
                                        <span className="text-sm text-gray-600 dark:text-gray-300 tabular-nums min-w-[4.5rem] text-center">
                                            {page} / {totalPages}
                                        </span>
                                        <button
                                            type="button"
                                            disabled={page >= totalPages}
                                            onClick={() => setPage((p) => Math.min(totalPages, p + 1))}
                                            className="w-8 h-8 rounded-full inline-flex items-center justify-center hover:bg-gray-100 dark:hover:bg-[#1a1c21] disabled:opacity-40 disabled:pointer-events-none transition-colors"
                                            aria-label={t('nextPage')}
                                        >
                                            <FiChevronRight className="w-5 h-5 text-[#525661] dark:text-gray-200" />
                                        </button>
                                    </>
                                ) : null}
                            </div>
                        </>
                    )}
                </div>

                <div className="bg-gray-50/80 dark:bg-[#121317] border-t border-gray-200/80 dark:border-gray-800 px-5 pt-4 pb-5">
                    <p className="text-sm leading-snug text-gray-900 dark:text-gray-100">
                        <span className="font-semibold">
                            {giftRecipient?.name ?? streamFallback.channelName} ({recipientPublicId})
                        </span>{' '}
                        <span className="text-gray-500 dark:text-gray-400">{t('recipientSuffix')}</span>
                    </p>

                    <div className="mt-3 rounded-xl border border-gray-200 dark:border-gray-800 bg-white dark:bg-[#0c0d0e] overflow-hidden">
                        <div className="flex items-center gap-3 px-4 py-3 min-h-[52px]">
                            <span className="shrink-0 text-sm text-gray-500 dark:text-gray-400">{t('coinBalance')}</span>
                            <div className="ml-auto flex items-center gap-1.5 min-w-0">
                                <CoinIcon
                                    className={GIFT_MODAL_SUMMARY_COIN_ICON_CLASS}
                                    size={GIFT_MODAL_SUMMARY_COIN_ICON_PX}
                                />
                                <span
                                    className={`text-base font-semibold tabular-nums truncate ${typeof coinBalance === 'number'
                                        ? 'text-gray-900 dark:text-gray-100'
                                        : 'text-gray-400 dark:text-gray-500'
                                        }`}
                                >
                                    {balanceDisplay}
                                </span>
                            </div>
                            <button
                                type="button"
                                className="shrink-0 h-8 px-3 rounded-lg border border-blue-600 text-blue-600 dark:border-blue-400 dark:text-blue-400 text-sm font-medium hover:bg-blue-50 dark:hover:bg-blue-500/10 transition-colors"
                            >
                                {t('buy')}
                            </button>
                        </div>

                        <div className="border-t border-gray-100 dark:border-gray-800 px-4 py-3 flex items-center gap-3 min-h-[48px]">
                            <span className="shrink-0 text-sm text-gray-500 dark:text-gray-400">{t('totalPrice')}</span>
                            <div className="ml-auto flex items-center justify-end gap-2 min-w-0">
                                {insufficientBalance ? (
                                    <span className="shrink-0 text-xs font-medium text-red-500 dark:text-red-400">
                                        {t('insufficientBalance')}
                                    </span>
                                ) : null}
                                {totalPrice > 0 ? (
                                    <CoinAmount amount={totalPrice} />
                                ) : (
                                    <span className="text-base font-semibold tabular-nums text-gray-400 dark:text-gray-500">0</span>
                                )}
                            </div>
                        </div>
                    </div>

                    <div className="mt-3 bg-white dark:bg-[#0c0d0e] border border-gray-200 dark:border-gray-800 rounded-xl px-4 h-12 flex items-center">
                        <div className="text-sm font-medium text-gray-900 dark:text-gray-100">{t('countLabel')}</div>
                        <div className="ml-auto flex items-center">
                            <button
                                type="button"
                                onClick={() => setGiftCount((v) => clampGiftSendCount(v - 1))}
                                className="w-8 h-8 rounded-full inline-flex items-center justify-center hover:bg-gray-100 dark:hover:bg-[#1a1c21] transition-colors"
                                aria-label={t('decrease')}
                            >
                                <FiMinus className="w-4 h-4 text-[#525661] dark:text-gray-200" />
                            </button>
                            <input
                                value={Number.isFinite(giftCount) ? String(giftCount) : ''}
                                onChange={(e) => setGiftCount(parseGiftCountInput(e.target.value))}
                                onFocus={(e) => e.currentTarget.select()}
                                max={GIFT_SEND_COUNT_MAX}
                                className="w-20 text-right text-xl font-semibold bg-transparent border-0 outline-none text-gray-900 dark:text-gray-100"
                                inputMode="numeric"
                                aria-label={t('countLabel')}
                            />
                            <span className="ml-1 text-sm font-medium text-gray-600 dark:text-gray-400">{t('unit')}</span>
                            <button
                                type="button"
                                onClick={() => setGiftCount((v) => clampGiftSendCount(v + 1))}
                                className="ml-1.5 w-8 h-8 rounded-full inline-flex items-center justify-center hover:bg-gray-100 dark:hover:bg-[#1a1c21] transition-colors"
                                aria-label={t('increase')}
                            >
                                <FiPlus className="w-4 h-4 text-[#525661] dark:text-gray-200" />
                            </button>
                            <button
                                type="button"
                                onClick={() => setGiftCount(0)}
                                className="ml-1 w-8 h-8 rounded-full inline-flex items-center justify-center hover:bg-gray-100 dark:hover:bg-[#1a1c21] transition-colors"
                                aria-label={t('clear')}
                            >
                                <FiX className="w-4 h-4 text-[#525661] dark:text-gray-200" />
                            </button>
                        </div>
                    </div>

                    <div className="mt-4 flex gap-3">
                        <button
                            type="button"
                            onClick={() => closeGift()}
                            className="flex-1 h-11 rounded-xl border border-gray-300 dark:border-gray-700 bg-white dark:bg-[#0c0d0e] text-gray-900 dark:text-gray-100 text-base hover:bg-gray-50 dark:hover:bg-[#121317] transition-colors"
                        >
                            {t('cancel')}
                        </button>
                        <button
                            type="button"
                            disabled={!giftSelected || giftCount <= 0 || giftSending || insufficientBalance}
                            onClick={() => onSendGift?.()}
                            className="flex-1 h-11 rounded-xl bg-blue-600 text-white text-base hover:bg-blue-700 active:bg-blue-800 disabled:opacity-50 disabled:pointer-events-none transition-colors"
                        >
                            {giftSending ? t('sendInProgress') : t('gift')}
                        </button>
                    </div>

                </div>
            </div>
        </div>
    )
}
