'use client'

import { useState, useEffect, useMemo, useRef, useCallback, type ReactNode } from 'react'
import { useRouter } from 'next/navigation'
import ConfirmModal from '@/components/ConfirmModal'
import GroupFamilyLogModal from '@/components/groups/GroupFamilyLogModal'
import GroupFamilySettingsModal from '@/components/groups/GroupFamilySettingsModal'
import Footer from '@/components/Footer'
import FamilyPageShell from '@/components/groups/FamilyPageShell'
import FamilyDetailSkeleton from './FamilyDetailSkeleton'
import LiveCard, { type LiveStream } from '@/components/LiveCard'
import { useTranslation } from 'react-i18next'
import type { TFunction } from 'i18next'
import { useToast } from '@/contexts/ToastContext'
import Image from 'next/image'
import Link from 'next/link'
import { createPortal } from 'react-dom'
import {
    FiUsers,
    FiUser,
    FiArrowLeft,
    FiChevronRight,
    FiUserPlus,
    FiSettings,
    FiLogOut,
    FiMoreVertical,
    FiX,
    FiRadio,
    FiCalendar,
    FiCheckCircle,
    FiBox,
} from 'react-icons/fi'
import {
    isGroupDeputyRole,
    isGroupLeaderRole,
    type GroupMemberAction,
} from '@/lib/groups/groupMemberRole'
import { MdVerified } from 'react-icons/md'
import { formatGroupMemberJoinAt, formatGroupMemberJoinDateTime, formatViews } from '@/utils/format'
import { resolveGroupRoleBadge } from '@/lib/groups/groupRoleBadge'
import { tipBelowOnlyClass } from '@/lib/ui/tipBelowOnlyClass'
import { resolveMediaUrl } from '@/lib/media/resolveMediaUrl'
import { hasValidImageSrc } from '@/lib/media/mediaGuards'
import ViewerCard from '@/app/room/_components/chat/ViewerCard'
import type { ParticipantItem, ViewerCardState } from '@/app/room/_components/types'

const DEFAULT_COVER = '/images/user/default_cover_v3.png'

interface FamilyMember {
    id: string
    displayName: string
    avatar: string | null
    followersCount: number
    totalViewsCount: number
    role: string
    contribution: number
    joinAt: number
}

interface FamilyLiveStream {
    roomId: string
    userId: string
    title: string
    viewers: number
    thumbnail: string | null
    startedAt: string | number | null
    isLive: boolean
    displayName: string
    avatar: string | null
}

interface GroupApplyApplicant {
    userId: string
    displayName: string
    avatar: string | null
    applicationAt: number
}

interface FamilyData {
    id: string
    name: string
    avatar: string | null
    banner: string | null
    description: string | null
    isVerified?: boolean
    isCanApplicapplication?: boolean
    groupLevelExp?: number
    artistsCount: number
    membersCount: number
    createdAt: string | number
    updatedAt: string | number
    members: FamilyMember[]
    liveStreams: FamilyLiveStream[]
    canManageGroupSettings?: boolean
    canReviewApplications?: boolean
    pendingApplications?: GroupApplyApplicant[]
}

interface FamilyDetailPageClientProps {
    groupId: string
}

function GroupAvatar({ avatar, name, className }: { avatar: string | null; name: string; className?: string }) {
    const src = resolveMediaUrl(avatar)
    const showImg = hasValidImageSrc(src)

    return (
        <div
            className={
                className ??
                'relative z-20 h-[100px] w-[100px] shrink-0 overflow-hidden rounded-2xl border-2 border-white bg-gray-100 shadow-md dark:border-white/20 dark:bg-neutral-800 sm:h-[120px] sm:w-[120px] md:h-[132px] md:w-[132px]'
            }
        >
            {showImg ? (
                // eslint-disable-next-line @next/next/no-img-element
                <img src={src} alt={name} className="h-full w-full object-cover" loading="lazy" decoding="async" />
            ) : (
                <span className="flex h-full w-full items-center justify-center text-gray-400 dark:text-gray-500">
                    <FiUsers className="h-10 w-10 sm:h-12 sm:w-12" strokeWidth={1.75} aria-hidden />
                </span>
            )}
        </div>
    )
}

function FamilyHubSubSection({
    title,
    icon: Icon,
    children,
}: {
    title: string
    icon: typeof FiRadio
    children: ReactNode
}) {
    return (
        <div className="overflow-visible rounded-2xl border border-gray-200 bg-white shadow-sm dark:border-white/10 dark:bg-[#0c0d0e] dark:shadow-[0_8px_30px_rgba(0,0,0,0.25)]">
            <div className="flex items-center gap-2 overflow-hidden rounded-t-2xl border-b border-gray-100 bg-gray-50/80 px-4 py-3.5 dark:border-white/10 dark:bg-white/[0.03] sm:px-5">
                <Icon className="h-5 w-5 shrink-0 text-gray-500 dark:text-gray-400" aria-hidden />
                <h3 className="text-base font-semibold text-gray-900 dark:text-white sm:text-lg">{title}</h3>
            </div>
            <div className="overflow-visible p-3 pb-5 sm:p-4 sm:pb-6 md:p-5 md:pb-7">{children}</div>
        </div>
    )
}

function FamilyMemberHub({
    liveStreams,
    t,
    onCheckInComingSoon,
}: {
    liveStreams: LiveStream[]
    t: TFunction
    onCheckInComingSoon: () => void
}) {
    return (
        <div className="mb-8 space-y-4 sm:mb-10 sm:space-y-5">
            <FamilyHubSubSection title={t('familys.hub.liveNow')} icon={FiRadio}>
                {liveStreams.length > 0 ? (
                    <div className="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3">
                        {liveStreams.map((stream) => (
                            <LiveCard key={stream.id} stream={stream} t={t} />
                        ))}
                    </div>
                ) : (
                    <p className="py-4 text-center text-sm text-gray-500 dark:text-gray-400">
                        {t('familys.hub.noLive')}
                    </p>
                )}
            </FamilyHubSubSection>

            <FamilyHubSubSection title={t('familys.hub.activities')} icon={FiCalendar}>
                <p className="py-4 text-center text-sm text-gray-500 dark:text-gray-400">
                    {t('familys.hub.noActivities')}
                </p>
            </FamilyHubSubSection>

            <FamilyHubSubSection title={t('familys.hub.dailyCheckIn')} icon={FiCheckCircle}>
                <div className="flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between">
                    <p className="text-sm text-gray-600 dark:text-gray-300">{t('familys.hub.checkInDesc')}</p>
                    <button
                        type="button"
                        tip={t('familys.actionComingSoon')}
                        onClick={onCheckInComingSoon}
                        className={`inline-flex h-10 shrink-0 items-center justify-center gap-2 rounded-[12px] border border-gray-200 bg-white px-5 text-xs font-medium text-gray-700 transition-colors hover:bg-gray-50 dark:border-white/15 dark:bg-black/25 dark:text-gray-100 dark:hover:bg-white/10 sm:min-w-[8.5rem] ${tipBelowOnlyClass}`}
                    >
                        <FiCheckCircle className="h-4 w-4 shrink-0" aria-hidden />
                        <span>{t('familys.hub.checkInButton')}</span>
                    </button>
                </div>
            </FamilyHubSubSection>
        </div>
    )
}

function MemberCardMenu({
    member,
    t,
    onAction,
}: {
    member: FamilyMember
    t: TFunction
    onAction: (member: FamilyMember, action: GroupMemberAction) => void | Promise<void>
}) {
    const [menuOpen, setMenuOpen] = useState(false)
    const [menuPos, setMenuPos] = useState({ top: 0, left: 0 })
    const triggerRef = useRef<HTMLButtonElement>(null)
    const menuPanelRef = useRef<HTMLDivElement>(null)

    const updateMenuPosition = useCallback(() => {
        const el = triggerRef.current
        if (!el) return
        const rect = el.getBoundingClientRect()
        setMenuPos({ top: rect.bottom + 4, left: rect.right })
    }, [])

    useEffect(() => {
        if (!menuOpen) return
        updateMenuPosition()
        const onDocMouseDown = (e: MouseEvent) => {
            const target = e.target as Node
            if (triggerRef.current?.contains(target) || menuPanelRef.current?.contains(target)) {
                return
            }
            setMenuOpen(false)
        }
        const onReposition = () => updateMenuPosition()
        document.addEventListener('mousedown', onDocMouseDown)
        window.addEventListener('resize', onReposition)
        window.addEventListener('scroll', onReposition, true)
        return () => {
            document.removeEventListener('mousedown', onDocMouseDown)
            window.removeEventListener('resize', onReposition)
            window.removeEventListener('scroll', onReposition, true)
        }
    }, [menuOpen, updateMenuPosition])

    const isLeader = isGroupLeaderRole(member.role)
    const isDeputy = isGroupDeputyRole(member.role)

    const items: Array<{ action: GroupMemberAction; label: string; danger?: boolean }> = []
    if (!isLeader) {
        items.push({ action: 'transfer_leader', label: t('familys.memberMenu.transferLeader') })
    }
    if (isDeputy) {
        items.push({ action: 'demote_member', label: t('familys.memberMenu.demoteMember') })
    }
    if (!isLeader && !isDeputy) {
        items.push({ action: 'promote_deputy', label: t('familys.memberMenu.promoteDeputy') })
    }
    items.push({ action: 'kick', label: t('familys.memberMenu.kick'), danger: true })

    const menuPanel =
        menuOpen && typeof document !== 'undefined' ? (
            <div
                ref={menuPanelRef}
                role="menu"
                className="fixed z-[200] min-w-[168px] overflow-hidden rounded-lg border border-gray-200 bg-white py-1 shadow-lg dark:border-gray-700 dark:bg-[#0c0d0e]"
                style={{
                    top: menuPos.top,
                    left: menuPos.left,
                    transform: 'translateX(-100%)',
                }}
            >
                {items.map((item) => (
                    <button
                        key={item.action}
                        type="button"
                        role="menuitem"
                        onClick={(e) => {
                            e.stopPropagation()
                            setMenuOpen(false)
                            void onAction(member, item.action)
                        }}
                        className={`block w-full px-3.5 py-2 text-left text-sm transition-colors ${
                            item.danger
                                ? 'text-red-600 hover:bg-red-50 dark:text-red-400 dark:hover:bg-red-950/40'
                                : 'text-gray-700 hover:bg-gray-100 dark:text-gray-200 dark:hover:bg-[#1a1c21]'
                        }`}
                    >
                        {item.label}
                    </button>
                ))}
            </div>
        ) : null

    return (
        <>
            <button
                ref={triggerRef}
                type="button"
                onClick={(e) => {
                    e.stopPropagation()
                    if (menuOpen) {
                        setMenuOpen(false)
                    } else {
                        updateMenuPosition()
                        setMenuOpen(true)
                    }
                }}
                className={`inline-flex h-8 w-8 shrink-0 items-center justify-center rounded-lg text-gray-500 transition-[opacity,background-color] duration-150 hover:bg-gray-200/80 dark:text-gray-400 dark:hover:bg-white/10 [@media(hover:hover)]:opacity-0 [@media(hover:hover)]:group-hover:opacity-100 focus-visible:opacity-100 [@media(hover:none)]:opacity-100 ${menuOpen ? 'opacity-100' : ''}`}
                aria-label={t('familys.memberMenu.moreOptions')}
                aria-expanded={menuOpen}
                aria-haspopup="menu"
            >
                <FiMoreVertical className="h-4 w-4" aria-hidden />
            </button>
            {menuPanel && createPortal(menuPanel, document.body)}
        </>
    )
}

function MemberCard({
    member,
    t,
    onSelect,
    canManage,
    showJoinAt,
    onMemberAction,
}: {
    member: FamilyMember
    t: TFunction
    onSelect: (member: FamilyMember) => void
    canManage: boolean
    showJoinAt: boolean
    onMemberAction: (member: FamilyMember, action: GroupMemberAction) => void | Promise<void>
}) {
    const avatarSrc = resolveMediaUrl(member.avatar)
    const showAvatar = hasValidImageSrc(avatarSrc)
    const joinAtLabel = showJoinAt ? formatGroupMemberJoinAt(member.joinAt) : ''
    const contributionValue = Number(member.contribution) || 0
    const contributionFormatted = formatViews(contributionValue)
    const memberMetaCapsuleClass =
        'inline-flex max-w-full items-center rounded-full bg-gray-100 px-2.5 py-1 text-xs font-medium text-gray-700 tabular-nums dark:bg-neutral-800 dark:text-gray-200 sm:px-3 sm:py-1.5'

    return (
        <div className="group flex w-full min-w-0 items-start gap-3 py-1 sm:py-1.5">
            <button
                type="button"
                onClick={() => onSelect(member)}
                className="relative h-12 w-12 shrink-0 overflow-hidden rounded-full bg-gray-200 ring-2 ring-white transition-opacity hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-gray-400 dark:bg-neutral-800 dark:ring-[#0c0d0e] dark:focus-visible:outline-white/50 sm:h-14 sm:w-14"
                aria-label={member.displayName}
            >
                {showAvatar ? (
                    // eslint-disable-next-line @next/next/no-img-element
                    <img
                        src={avatarSrc}
                        alt=""
                        className="h-full w-full object-cover"
                        loading="lazy"
                        decoding="async"
                    />
                ) : (
                    <span className="flex h-full w-full items-center justify-center text-gray-400">
                        <FiUser className="h-6 w-6" aria-hidden />
                    </span>
                )}
            </button>
            <div className="min-w-0 flex-1">
                <div className="flex min-w-0 items-center gap-2">
                    <span className="truncate text-sm font-semibold text-gray-900 dark:text-gray-100 sm:text-base">
                        {member.displayName}
                    </span>
                    <MemberRoleBadge role={member.role} t={t} />
                </div>
                <div className="mt-1.5 flex flex-wrap items-center gap-1.5 sm:gap-2">
                    {joinAtLabel ? (
                        <span
                            className={memberMetaCapsuleClass}
                            aria-label={t('familys.memberJoinedAt', { date: joinAtLabel })}
                        >
                            <span className="truncate">
                                {t('familys.memberJoinedAt', { date: joinAtLabel })}
                            </span>
                        </span>
                    ) : null}
                    <span
                        className={memberMetaCapsuleClass}
                        aria-label={t('familys.memberContributionAria', {
                            value: contributionFormatted,
                        })}
                    >
                        <span className="truncate">
                            {t('familys.memberContributionLine', { value: contributionFormatted })}
                        </span>
                    </span>
                </div>
            </div>
            {canManage ? (
                <div className="shrink-0 self-center">
                    <MemberCardMenu member={member} t={t} onAction={onMemberAction} />
                </div>
            ) : null}
        </div>
    )
}

const GROUP_ROLE_ICON = {
    leader: '/images/group/host.png',
    deputy: '/images/group/deputy_host.png',
} as const

/** 原圖 1210×900；顯示 16px 高，請求 2x 尺寸由 next/image 縮放以避免瀏覽器縮小整張圖發糊 */
const GROUP_ROLE_ICON_DISPLAY_H = 16
const GROUP_ROLE_ICON_ASPECT = 1210 / 900
const GROUP_ROLE_ICON_DISPLAY_W = Math.round(GROUP_ROLE_ICON_DISPLAY_H * GROUP_ROLE_ICON_ASPECT)
const GROUP_ROLE_ICON_IMG_H = GROUP_ROLE_ICON_DISPLAY_H * 2
const GROUP_ROLE_ICON_IMG_W = Math.round(GROUP_ROLE_ICON_IMG_H * GROUP_ROLE_ICON_ASPECT)

function MemberRoleBadge({ role, t }: { role: string; t: TFunction }) {
    const badge = resolveGroupRoleBadge(role)
    if (!badge) return null
    const isLeader = badge === 'leader'
    const label = isLeader ? t('familys.familyLeader') : t('familys.familyDeputyLeader')
    const src = isLeader ? GROUP_ROLE_ICON.leader : GROUP_ROLE_ICON.deputy

    return (
        <span
            tip={label}
            className={`inline-flex shrink-0 items-center ${tipBelowOnlyClass}`}
            aria-label={label}
        >
            <Image
                src={src}
                alt=""
                width={GROUP_ROLE_ICON_IMG_W}
                height={GROUP_ROLE_ICON_IMG_H}
                className="object-contain"
                style={{
                    width: GROUP_ROLE_ICON_DISPLAY_W,
                    height: GROUP_ROLE_ICON_DISPLAY_H,
                }}
                sizes={`${GROUP_ROLE_ICON_DISPLAY_W}px`}
            />
        </span>
    )
}

function FamilyBackFab({ label }: { label: string }) {
    return (
        <Link
            href="/groups"
            className="fixed left-4 top-[calc(80px)] z-40 inline-flex h-10 max-w-[calc(100vw-2rem)] items-center gap-2 rounded-[12px] border border-gray-200 bg-white/90 px-4 text-xs font-medium text-gray-700 shadow-sm backdrop-blur-md transition-colors hover:bg-gray-50 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-gray-400 dark:border-white/15 dark:bg-black/25 dark:text-gray-100 dark:shadow-[0_4px_20px_rgba(0,0,0,0.35)] dark:hover:bg-white/10 dark:focus-visible:outline-white/70 sm:left-6 sm:max-w-none md:left-8"
            aria-label={label}
        >
            <FiArrowLeft className="h-4 w-4 shrink-0 opacity-80" aria-hidden />
            <span className="truncate">{label}</span>
        </Link>
    )
}

function MemberListHeaderMenu({
    t,
    pendingCount,
    onOpenReview,
    onOpenLogs,
}: {
    t: TFunction
    pendingCount: number
    onOpenReview: () => void
    onOpenLogs: () => void
}) {
    const [menuOpen, setMenuOpen] = useState(false)
    const [menuPos, setMenuPos] = useState({ top: 0, left: 0 })
    const triggerRef = useRef<HTMLButtonElement>(null)
    const menuPanelRef = useRef<HTMLDivElement>(null)

    const updateMenuPosition = useCallback(() => {
        const el = triggerRef.current
        if (!el) return
        const rect = el.getBoundingClientRect()
        setMenuPos({ top: rect.bottom + 4, left: rect.right })
    }, [])

    useEffect(() => {
        if (!menuOpen) return
        updateMenuPosition()
        const onDocMouseDown = (e: MouseEvent) => {
            const target = e.target as Node
            if (triggerRef.current?.contains(target) || menuPanelRef.current?.contains(target)) {
                return
            }
            setMenuOpen(false)
        }
        const onReposition = () => updateMenuPosition()
        document.addEventListener('mousedown', onDocMouseDown)
        window.addEventListener('resize', onReposition)
        window.addEventListener('scroll', onReposition, true)
        return () => {
            document.removeEventListener('mousedown', onDocMouseDown)
            window.removeEventListener('resize', onReposition)
            window.removeEventListener('scroll', onReposition, true)
        }
    }, [menuOpen, updateMenuPosition])

    const menuPanel =
        menuOpen && typeof document !== 'undefined' ? (
            <div
                ref={menuPanelRef}
                role="menu"
                className="fixed z-[200] min-w-[180px] overflow-hidden rounded-lg border border-gray-200 bg-white py-1 shadow-lg dark:border-gray-700 dark:bg-[#0c0d0e]"
                style={{
                    top: menuPos.top,
                    left: menuPos.left,
                    transform: 'translateX(-100%)',
                }}
            >
                <button
                    type="button"
                    role="menuitem"
                    onClick={(e) => {
                        e.stopPropagation()
                        setMenuOpen(false)
                        onOpenReview()
                    }}
                    className="flex w-full items-center justify-between gap-3 px-3.5 py-2 text-left text-sm text-gray-700 transition-colors hover:bg-gray-100 dark:text-gray-200 dark:hover:bg-[#1a1c21]"
                >
                    <span>{t('familys.applications.reviewMenu')}</span>
                    {pendingCount > 0 ? (
                        <span
                            className={`inline-flex h-[18px] shrink-0 items-center justify-center rounded bg-red-500 text-[10px] font-semibold tabular-nums leading-none text-white ${pendingCount > 9 ? 'min-w-[22px] px-1' : 'w-[18px]'}`}
                        >
                            {pendingCount > 99 ? '99+' : pendingCount}
                        </span>
                    ) : null}
                </button>
                <button
                    type="button"
                    role="menuitem"
                    onClick={(e) => {
                        e.stopPropagation()
                        setMenuOpen(false)
                        onOpenLogs()
                    }}
                    className="flex w-full px-3.5 py-2 text-left text-sm text-gray-700 transition-colors hover:bg-gray-100 dark:text-gray-200 dark:hover:bg-[#1a1c21]"
                >
                    {t('familys.logs.menu')}
                </button>
            </div>
        ) : null

    const hasPending = pendingCount > 0

    return (
        <>
            <span className="relative inline-flex shrink-0">
                <button
                    ref={triggerRef}
                    type="button"
                    onClick={(e) => {
                        e.stopPropagation()
                        if (menuOpen) {
                            setMenuOpen(false)
                        } else {
                            updateMenuPosition()
                            setMenuOpen(true)
                        }
                    }}
                    className={`inline-flex h-8 w-8 items-center justify-center rounded-lg text-gray-500 transition-colors hover:bg-gray-200/80 dark:text-gray-400 dark:hover:bg-white/10 ${menuOpen ? 'bg-gray-200/80 dark:bg-white/10' : ''}`}
                    aria-label={
                        hasPending
                            ? `${t('familys.applications.reviewMenu')} (${pendingCount})`
                            : t('familys.memberMenu.moreOptions')
                    }
                    aria-expanded={menuOpen}
                    aria-haspopup="menu"
                >
                    <FiMoreVertical className="h-4 w-4" aria-hidden />
                </button>
                {hasPending ? (
                    <span
                        className="pointer-events-none absolute right-0 top-0 z-10 h-2 w-2 rounded bg-red-500 ring-2 ring-white dark:ring-[#f3f4f6]"
                        aria-hidden
                    />
                ) : null}
            </span>
            {menuPanel && createPortal(menuPanel, document.body)}
        </>
    )
}

function GroupApplyReviewModal({
    isOpen,
    closing,
    entering,
    onClose,
    applicants,
    t,
    onReview,
    busyUserId,
}: {
    isOpen: boolean
    closing: boolean
    entering: boolean
    onClose: () => void
    applicants: GroupApplyApplicant[]
    t: TFunction
    onReview: (applicant: GroupApplyApplicant, action: 'approve' | 'reject') => void
    busyUserId: string | null
}) {
    if (!isOpen) return null

    return (
        <div
            className={`fixed inset-0 z-[600] flex items-center justify-center p-3 transition-opacity duration-200 ease-[cubic-bezier(0.56,0.12,0.12,0.98)] ${closing || entering ? 'pointer-events-none opacity-0' : 'opacity-100'}`}
        >
            <div className="absolute inset-0 bg-black/60" onClick={onClose} aria-hidden />
            <div
                role="dialog"
                aria-modal="true"
                aria-labelledby="group-apply-review-title"
                className={`relative flex max-h-[min(85vh,640px)] w-full max-w-lg flex-col overflow-hidden rounded-xl border border-gray-200 bg-white shadow-2xl transition-[opacity,transform] duration-200 ease-[cubic-bezier(0.56,0.12,0.12,0.98)] dark:border-gray-800 dark:bg-[#0c0d0e] ${closing || entering ? 'scale-95 opacity-0' : 'scale-100 opacity-100'}`}
            >
                <div className="flex shrink-0 items-center justify-between gap-3 border-b border-gray-100 px-5 py-4 dark:border-white/10">
                    <h3
                        id="group-apply-review-title"
                        className="flex min-w-0 items-center gap-2 text-lg font-semibold text-gray-900 dark:text-white"
                    >
                        <FiUserPlus
                            className="h-5 w-5 shrink-0 text-gray-500 dark:text-gray-400"
                            aria-hidden
                        />
                        <span className="truncate">{t('familys.applications.modalTitle')}</span>
                    </h3>
                    <button
                        type="button"
                        onClick={onClose}
                        className="inline-flex h-8 w-8 items-center justify-center rounded-full text-gray-500 transition-colors hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-[#1a1c21]"
                        aria-label={t('common.close')}
                    >
                        <FiX className="h-4.5 w-4.5" aria-hidden />
                    </button>
                </div>
                <div className="min-h-0 flex-1 overflow-y-auto p-4">
                    {applicants.length === 0 ? (
                        <p className="py-8 text-center text-sm text-gray-500 dark:text-gray-400">
                            {t('familys.applications.emptyList')}
                        </p>
                    ) : (
                        <div>
                            {applicants.map((applicant) => (
                                <GroupApplyReviewCard
                                    key={applicant.userId}
                                    applicant={applicant}
                                    t={t}
                                    onReview={onReview}
                                    busyUserId={busyUserId}
                                />
                            ))}
                        </div>
                    )}
                </div>
            </div>
        </div>
    )
}

function GroupApplyReviewCard({
    applicant,
    t,
    onReview,
    busyUserId,
}: {
    applicant: GroupApplyApplicant
    t: TFunction
    onReview: (applicant: GroupApplyApplicant, action: 'approve' | 'reject') => void
    busyUserId: string | null
}) {
    const isBusy = busyUserId === applicant.userId
    const avatarSrc = resolveMediaUrl(applicant.avatar)

    return (
        <div className="flex items-center gap-3 border-b border-gray-100 py-3 last:border-b-0 dark:border-white/10">
            <div className="flex min-w-0 flex-1 items-center gap-3">
                <div className="h-11 w-11 shrink-0 overflow-hidden rounded-full bg-gray-200 dark:bg-neutral-800">
                    {hasValidImageSrc(avatarSrc) ? (
                        // eslint-disable-next-line @next/next/no-img-element
                        <img
                            src={avatarSrc}
                            alt=""
                            className="h-full w-full object-cover"
                            loading="lazy"
                        />
                    ) : (
                        <span className="flex h-full w-full items-center justify-center text-gray-400">
                            <FiUser className="h-5 w-5" aria-hidden />
                        </span>
                    )}
                </div>
                <div className="min-w-0">
                    <p className="truncate text-sm font-medium text-gray-900 dark:text-white">
                        {applicant.displayName}
                    </p>
                    <p className="text-xs text-gray-500 dark:text-gray-400">
                        {t('familys.applications.submittedAt', {
                            date: formatGroupMemberJoinDateTime(applicant.applicationAt),
                        })}
                    </p>
                </div>
            </div>
            <div className="ml-auto flex shrink-0 items-center gap-2">
                <button
                    type="button"
                    disabled={isBusy}
                    onClick={() => onReview(applicant, 'reject')}
                    className="inline-flex h-9 items-center justify-center rounded-lg border border-gray-900/20 bg-white px-3 text-xs font-medium text-gray-900 transition-colors hover:bg-gray-100 disabled:opacity-50 dark:border-white/25 dark:bg-transparent dark:text-white dark:hover:bg-white/10"
                >
                    {t('familys.applications.reject')}
                </button>
                <button
                    type="button"
                    disabled={isBusy}
                    onClick={() => onReview(applicant, 'approve')}
                    className="inline-flex h-9 items-center justify-center rounded-lg border border-gray-900 bg-gray-900 px-3 text-xs font-medium text-white transition-colors hover:bg-gray-800 disabled:opacity-50 dark:border-white dark:bg-white dark:text-gray-900 dark:hover:bg-gray-100"
                >
                    {t('familys.applications.approve')}
                </button>
            </div>
        </div>
    )
}

export default function FamilyDetailPageClient({ groupId }: FamilyDetailPageClientProps) {
    const router = useRouter()
    const { t } = useTranslation()
    const { showToast } = useToast()
    const [sidebarOpen, setSidebarOpen] = useState(false)
    const [familyData, setFamilyData] = useState<FamilyData | null>(null)
    const [currentUserId, setCurrentUserId] = useState<string | null>(null)
    const [applyPending, setApplyPending] = useState(false)
    const [isLoading, setIsLoading] = useState(true)
    const [viewerCard, setViewerCard] = useState<ViewerCardState | null>(null)
    const [viewerCardDepth, setViewerCardDepth] = useState<'root' | 'gift' | 'admin'>('root')
    const viewerCardRef = useRef<HTMLDivElement>(null)
    const confirmRef = useRef<HTMLDivElement>(null)
    const pendingMemberActionRef = useRef<{
        member: FamilyMember
        action: GroupMemberAction
    } | null>(null)
    const pendingLeaveFamilyRef = useRef(false)
    const [confirmModalOpen, setConfirmModalOpen] = useState(false)
    const [confirmClosing, setConfirmClosing] = useState(false)
    const [confirmEntering, setConfirmEntering] = useState(false)
    const [confirmTitle, setConfirmTitle] = useState('')
    const [confirmMessage, setConfirmMessage] = useState('')
    const [confirmNote, setConfirmNote] = useState<string | undefined>(undefined)
    const [confirmConfirmText, setConfirmConfirmText] = useState<string | undefined>(undefined)
    const [confirmSeverity, setConfirmSeverity] = useState<'info' | 'warning' | 'danger'>('warning')
    const [confirmIsAlert, setConfirmIsAlert] = useState(false)
    const [applySubmitting, setApplySubmitting] = useState(false)
    const [reviewBusyUserId, setReviewBusyUserId] = useState<string | null>(null)
    const [applyReviewModalOpen, setApplyReviewModalOpen] = useState(false)
    const [applyReviewClosing, setApplyReviewClosing] = useState(false)
    const [applyReviewEntering, setApplyReviewEntering] = useState(false)
    const [familyLogModalOpen, setFamilyLogModalOpen] = useState(false)
    const [familyLogClosing, setFamilyLogClosing] = useState(false)
    const [familyLogEntering, setFamilyLogEntering] = useState(false)
    const [settingsModalOpen, setSettingsModalOpen] = useState(false)
    const [settingsClosing, setSettingsClosing] = useState(false)
    const [settingsEntering, setSettingsEntering] = useState(false)

    const openMemberViewerCard = useCallback((member: FamilyMember) => {
        const participant: ParticipantItem = {
            role: member.role,
            name: member.displayName,
            id: member.id,
            avatarUrl: member.avatar ?? undefined,
            profileApiKey: member.id,
        }
        setViewerCardDepth('root')
        setViewerCard((prev) => {
            if (prev?.user.id === member.id) return null
            return { mode: 'desktop', user: participant, top: 0, left: 0 }
        })
    }, [])

    const closeViewerCard = useCallback(() => {
        setViewerCard(null)
        setViewerCardDepth('root')
    }, [])

    const canManageMembers = Boolean(familyData?.canManageGroupSettings)

    useEffect(() => {
        let cancelled = false
        const loadCurrentUser = async () => {
            try {
                const res = await fetch('/api/profile/user-info', { credentials: 'include' })
                const data = await res.json()
                if (cancelled) return
                const id =
                    data?.ok && data?.id != null
                        ? String(data.id).trim()
                        : data?.ok && data?.user?.id != null
                          ? String(data.user.id).trim()
                          : ''
                setCurrentUserId(id || null)
            } catch {
                if (!cancelled) setCurrentUserId(null)
            }
        }
        void loadCurrentUser()
        return () => {
            cancelled = true
        }
    }, [])

    const viewerIsMember = useMemo(() => {
        if (!familyData || !currentUserId) return false
        return familyData.members.some((m) => m.id === currentUserId)
    }, [familyData, currentUserId])

    const isCanApplicapplication = familyData?.isCanApplicapplication !== false

    const showApplyJoinButton = useMemo(() => {
        if (!familyData) return false
        return !viewerIsMember
    }, [familyData, viewerIsMember])

    const applyJoinDisabled =
        applySubmitting || applyPending || !isCanApplicapplication

    const applyJoinTip = useMemo(() => {
        if (applyPending) return t('familys.applyJoinPending')
        if (!isCanApplicapplication) return t('familys.applyJoinClosed')
        return t('familys.applyJoin')
    }, [applyPending, isCanApplicapplication, t])

    const applyJoinLabel = applyPending
        ? t('familys.applyJoinPending')
        : t('familys.applyJoin')

    const showLeaveFamilyButton = useMemo(() => {
        if (!familyData || !currentUserId || !viewerIsMember) return false
        const me = familyData.members.find((m) => m.id === currentUserId)
        if (!me) return false
        return !isGroupLeaderRole(me.role)
    }, [currentUserId, familyData, viewerIsMember])

    const canViewMemberJoinTime = useMemo(() => {
        if (!familyData || !currentUserId) return false
        const me = familyData.members.find((m) => m.id === currentUserId)
        if (!me) return false
        return isGroupLeaderRole(me.role) || isGroupDeputyRole(me.role)
    }, [currentUserId, familyData])

    const pendingApplications = useMemo(
        () => familyData?.pendingApplications ?? [],
        [familyData?.pendingApplications]
    )

    const canReviewApplications = Boolean(familyData?.canReviewApplications)

    const showMemberListSection = Boolean(familyData && viewerIsMember)

    const openApplyReviewModal = useCallback(() => {
        setApplyReviewEntering(true)
        setApplyReviewModalOpen(true)
        setApplyReviewClosing(false)
        requestAnimationFrame(() => requestAnimationFrame(() => setApplyReviewEntering(false)))
    }, [])

    const closeApplyReviewModal = useCallback(() => {
        setApplyReviewClosing(true)
        window.setTimeout(() => {
            setApplyReviewModalOpen(false)
            setApplyReviewClosing(false)
        }, 200)
    }, [])

    const openFamilyLogModal = useCallback(() => {
        setFamilyLogEntering(true)
        setFamilyLogModalOpen(true)
        setFamilyLogClosing(false)
        requestAnimationFrame(() => requestAnimationFrame(() => setFamilyLogEntering(false)))
    }, [])

    const closeFamilyLogModal = useCallback(() => {
        setFamilyLogClosing(true)
        window.setTimeout(() => {
            setFamilyLogModalOpen(false)
            setFamilyLogClosing(false)
        }, 200)
    }, [])

    const openSettingsModal = useCallback(() => {
        setSettingsEntering(true)
        setSettingsModalOpen(true)
        setSettingsClosing(false)
        requestAnimationFrame(() => requestAnimationFrame(() => setSettingsEntering(false)))
    }, [])

    const closeSettingsModal = useCallback(() => {
        setSettingsClosing(true)
        window.setTimeout(() => {
            setSettingsModalOpen(false)
            setSettingsClosing(false)
        }, 200)
    }, [])

    const refreshApplyPending = useCallback(async () => {
        if (!groupId) {
            setApplyPending(false)
            return
        }
        try {
            const res = await fetch(`/api/group/${encodeURIComponent(groupId)}/apply/status`, {
                credentials: 'include',
            })
            const json = (await res.json()) as { ok?: boolean; pending?: boolean }
            setApplyPending(Boolean(json.ok && json.pending))
        } catch {
            setApplyPending(false)
        }
    }, [groupId])

    useEffect(() => {
        if (!groupId || !currentUserId || viewerIsMember) {
            setApplyPending(false)
            return
        }
        void refreshApplyPending()
    }, [groupId, currentUserId, viewerIsMember, refreshApplyPending])

    const reloadFamilyData = useCallback(async () => {
        if (!groupId) return
        try {
            const response = await fetch(`/api/group/${encodeURIComponent(groupId)}`, {
                credentials: 'include',
            })
            const result = await response.json()
            if (result.ok) {
                setFamilyData(result.data)
            }
            await refreshApplyPending()
        } catch {
            // ignore
        }
    }, [groupId, refreshApplyPending])

    const handleSettingsSaved = useCallback(async () => {
        await reloadFamilyData()
        showToast(t('familys.settings.saveSuccess'), 'success')
    }, [reloadFamilyData, showToast, t])

    useEffect(() => {
        if (!groupId) {
            setFamilyData(null)
            setIsLoading(false)
            return
        }

        let cancelled = false
        const fetchFamilyData = async () => {
            setIsLoading(true)
            try {
                const response = await fetch(`/api/group/${encodeURIComponent(groupId)}`, {
                    credentials: 'include',
                })
                const result = await response.json()
                if (cancelled) return
                if (result.ok) {
                    setFamilyData(result.data)
                } else {
                    setFamilyData(null)
                }
                if (!cancelled) {
                    await refreshApplyPending()
                }
            } catch {
                if (!cancelled) {
                    setFamilyData(null)
                }
            } finally {
                if (!cancelled) {
                    setIsLoading(false)
                }
            }
        }
        void fetchFamilyData()
        return () => {
            cancelled = true
        }
    }, [groupId, refreshApplyPending])

    const closeMemberConfirm = useCallback(() => {
        setConfirmEntering(false)
        setConfirmClosing(true)
        window.setTimeout(() => {
            setConfirmModalOpen(false)
            setConfirmClosing(false)
            setConfirmTitle('')
            setConfirmMessage('')
            setConfirmNote(undefined)
            setConfirmConfirmText(undefined)
            setConfirmSeverity('warning')
            setConfirmIsAlert(false)
            pendingMemberActionRef.current = null
            pendingLeaveFamilyRef.current = false
        }, 200)
    }, [])

    const openAlertModal = useCallback(
        (title: string, message: string, severity: 'info' | 'warning' = 'info') => {
            pendingMemberActionRef.current = null
            pendingLeaveFamilyRef.current = false
            setConfirmIsAlert(true)
            setConfirmTitle(title)
            setConfirmMessage(message)
            setConfirmNote(undefined)
            setConfirmConfirmText(t('common.confirm'))
            setConfirmSeverity(severity)
            setConfirmEntering(true)
            setConfirmModalOpen(true)
            setConfirmClosing(false)
            requestAnimationFrame(() => requestAnimationFrame(() => setConfirmEntering(false)))
        },
        [t]
    )

    const handleCheckInComingSoon = useCallback(() => {
        openAlertModal(t('familys.hub.dailyCheckIn'), t('familys.actionComingSoon'), 'info')
    }, [openAlertModal, t])

    const openMemberConfirm = useCallback(
        (
            member: FamilyMember,
            action: GroupMemberAction,
            title: string,
            message: string,
            confirmText: string,
            severity: 'warning' | 'danger',
            note?: string
        ) => {
            pendingLeaveFamilyRef.current = false
            pendingMemberActionRef.current = { member, action }
            setConfirmIsAlert(false)
            setConfirmTitle(title)
            setConfirmMessage(message)
            setConfirmNote(note)
            setConfirmConfirmText(confirmText)
            setConfirmSeverity(severity)
            setConfirmEntering(true)
            setConfirmModalOpen(true)
            setConfirmClosing(false)
            requestAnimationFrame(() => requestAnimationFrame(() => setConfirmEntering(false)))
        },
        []
    )

    const executeMemberAction = useCallback(
        async (member: FamilyMember, action: GroupMemberAction) => {
            try {
                const res = await fetch(
                    `/api/group/${encodeURIComponent(groupId)}/members/${encodeURIComponent(member.id)}`,
                    {
                        method: 'PATCH',
                        headers: { 'Content-Type': 'application/json' },
                        body: JSON.stringify({ action }),
                    }
                )
                const json = (await res.json()) as { ok?: boolean; message?: string }
                if (!res.ok || !json.ok) {
                    window.alert(json.message || t('familys.memberMenu.actionFailed'))
                    return
                }
                if (action === 'transfer_leader') {
                    showToast(
                        t('familys.memberMenu.transferLeaderSuccess', { name: member.displayName }),
                        'success'
                    )
                }
                await reloadFamilyData()
            } catch {
                window.alert(t('familys.memberMenu.actionFailed'))
            }
        },
        [groupId, t, reloadFamilyData, showToast]
    )

    const executeLeaveFamily = useCallback(async () => {
        if (!currentUserId) return
        try {
            const res = await fetch(
                `/api/group/${encodeURIComponent(groupId)}/members/${encodeURIComponent(currentUserId)}`,
                { method: 'DELETE' }
            )
            const json = (await res.json()) as { ok?: boolean; message?: string }
            if (!res.ok || !json.ok) {
                window.alert(json.message || t('familys.leaveFamilyFailed'))
                return
            }
            await reloadFamilyData()
        } catch {
            window.alert(t('familys.leaveFamilyFailed'))
        }
    }, [groupId, currentUserId, t, reloadFamilyData])

    const handleApplyJoin = useCallback(async () => {
        if (!currentUserId) {
            router.push(`/login?next=${encodeURIComponent(`/groups/${groupId}`)}`)
            return
        }
        if (applySubmitting || applyPending || !isCanApplicapplication) return
        setApplySubmitting(true)
        try {
            const res = await fetch(`/api/group/${encodeURIComponent(groupId)}/apply`, {
                method: 'POST',
                credentials: 'include',
            })
            const json = (await res.json()) as { ok?: boolean; message?: string }
            if (!res.ok || !json.ok) {
                if (res.status === 403) {
                    openAlertModal(t('familys.applyJoin'), t('familys.applyJoinClosed'), 'info')
                } else {
                    openAlertModal(
                        t('familys.applyJoin'),
                        json.message || t('familys.applyJoinFailed'),
                        'warning'
                    )
                }
                return
            }
            showToast(t('familys.applyJoinSuccess'), 'success')
            await reloadFamilyData()
        } catch {
            openAlertModal(t('familys.applyJoin'), t('familys.applyJoinFailed'), 'warning')
        } finally {
            setApplySubmitting(false)
        }
    }, [
        applySubmitting,
        currentUserId,
        groupId,
        reloadFamilyData,
        router,
        showToast,
        t,
        applyPending,
        isCanApplicapplication,
        openAlertModal,
    ])

    const handleReviewApplication = useCallback(
        async (applicant: GroupApplyApplicant, action: 'approve' | 'reject') => {
            if (reviewBusyUserId) return
            setReviewBusyUserId(applicant.userId)
            try {
                const res = await fetch(
                    `/api/group/${encodeURIComponent(groupId)}/apply/${encodeURIComponent(applicant.userId)}`,
                    {
                        method: 'PATCH',
                        credentials: 'include',
                        headers: { 'Content-Type': 'application/json' },
                        body: JSON.stringify({ action }),
                    }
                )
                const json = (await res.json()) as { ok?: boolean; message?: string }
                if (!res.ok || !json.ok) {
                    window.alert(json.message || t('familys.applications.reviewFailed'))
                    return
                }
                showToast(
                    action === 'approve'
                        ? t('familys.applications.approveSuccess', { name: applicant.displayName })
                        : t('familys.applications.rejectSuccess', { name: applicant.displayName }),
                    'success'
                )
                await reloadFamilyData()
            } catch {
                window.alert(t('familys.applications.reviewFailed'))
            } finally {
                setReviewBusyUserId(null)
            }
        },
        [groupId, reloadFamilyData, reviewBusyUserId, showToast, t]
    )

    const openLeaveFamilyConfirm = useCallback(() => {
        if (!familyData) return
        pendingMemberActionRef.current = null
        pendingLeaveFamilyRef.current = true
        setConfirmIsAlert(false)
        setConfirmTitle(t('familys.leaveFamily'))
        setConfirmMessage(t('familys.confirmLeaveFamily', { name: familyData.name }))
        setConfirmNote(undefined)
        setConfirmConfirmText(t('familys.leaveFamily'))
        setConfirmSeverity('danger')
        setConfirmEntering(true)
        setConfirmModalOpen(true)
        setConfirmClosing(false)
        requestAnimationFrame(() => requestAnimationFrame(() => setConfirmEntering(false)))
    }, [familyData, t])

    const handleConfirmMemberAction = useCallback(async () => {
        if (confirmIsAlert) {
            closeMemberConfirm()
            return
        }
        if (pendingLeaveFamilyRef.current) {
            pendingLeaveFamilyRef.current = false
            closeMemberConfirm()
            await executeLeaveFamily()
            return
        }
        const pending = pendingMemberActionRef.current
        if (!pending) {
            closeMemberConfirm()
            return
        }
        const { member, action } = pending
        pendingMemberActionRef.current = null
        closeMemberConfirm()
        await executeMemberAction(member, action)
    }, [closeMemberConfirm, confirmIsAlert, executeMemberAction, executeLeaveFamily])

    const handleMemberAction = useCallback(
        async (member: FamilyMember, action: GroupMemberAction) => {
            const name = member.displayName
            const confirmByAction: Partial<
                Record<
                    GroupMemberAction,
                    {
                        title: string
                        message: string
                        note?: string
                        confirmText: string
                        severity: 'warning' | 'danger'
                    }
                >
            > = {
                transfer_leader: {
                    title: t('familys.memberMenu.transferLeader'),
                    message: t('familys.memberMenu.confirmTransferLeader', { name }),
                    note: t('familys.memberMenu.confirmTransferLeaderNote'),
                    confirmText: t('familys.memberMenu.transferLeader'),
                    severity: 'warning',
                },
                demote_member: {
                    title: t('familys.memberMenu.demoteMember'),
                    message: t('familys.memberMenu.confirmDemoteMember', { name }),
                    confirmText: t('familys.memberMenu.demoteMember'),
                    severity: 'warning',
                },
                promote_deputy: {
                    title: t('familys.memberMenu.promoteDeputy'),
                    message: t('familys.memberMenu.confirmPromoteDeputy', { name }),
                    confirmText: t('familys.memberMenu.promoteDeputy'),
                    severity: 'warning',
                },
                kick: {
                    title: t('familys.memberMenu.kick'),
                    message: t('familys.memberMenu.confirmKick', { name }),
                    confirmText: t('familys.memberMenu.kick'),
                    severity: 'danger',
                },
            }
            const confirm = confirmByAction[action]
            if (confirm) {
                openMemberConfirm(
                    member,
                    action,
                    confirm.title,
                    confirm.message,
                    confirm.confirmText,
                    confirm.severity,
                    confirm.note
                )
                return
            }
            await executeMemberAction(member, action)
        },
        [openMemberConfirm, executeMemberAction, t]
    )

    const coverUrl = useMemo(() => {
        if (!familyData) return DEFAULT_COVER
        const bannerResolved = resolveMediaUrl(familyData.banner)
        if (hasValidImageSrc(bannerResolved)) return bannerResolved
        return DEFAULT_COVER
    }, [familyData])

    if (isLoading) {
        return (
            <FamilyPageShell
                sidebarOpen={sidebarOpen}
                onMenuClick={() => setSidebarOpen(true)}
                onSidebarClose={() => setSidebarOpen(false)}
            >
                <FamilyDetailSkeleton />
            </FamilyPageShell>
        )
    }

    if (!familyData) {
        return (
            <FamilyPageShell
                sidebarOpen={sidebarOpen}
                onMenuClick={() => setSidebarOpen(true)}
                onSidebarClose={() => setSidebarOpen(false)}
            >
                <main className="flex flex-1 min-w-0 items-center justify-center px-4 py-20 sm:px-8 md:px-[120px]">
                    <div className="mx-auto max-w-md text-center">
                        <div className="mx-auto mb-4 flex h-16 w-16 items-center justify-center rounded-full bg-gray-100 dark:bg-neutral-900">
                            <FiUsers className="h-8 w-8 text-gray-400 dark:text-gray-500" aria-hidden />
                        </div>
                        <h2 className="mb-2 text-xl font-semibold text-gray-900 dark:text-white sm:text-2xl">
                            {t('familys.notFound')}
                        </h2>
                        <p className="mb-6 text-sm text-gray-500 dark:text-gray-400">{t('familys.notFoundDesc')}</p>
                        <Link
                            href="/groups"
                            className="inline-flex items-center gap-2 rounded-[12px] border border-gray-200 bg-white px-4 py-2.5 text-sm font-medium text-gray-700 shadow-sm transition-colors hover:bg-gray-50 dark:border-white/15 dark:bg-black/25 dark:text-gray-100 dark:hover:bg-white/10"
                        >
                            <FiArrowLeft className="h-4 w-4" aria-hidden />
                            {t('familys.backToList')}
                        </Link>
                    </div>
                </main>
                <Footer />
            </FamilyPageShell>
        )
    }

    const liveStreams: LiveStream[] = familyData.liveStreams.map((ls) => ({
        id: ls.roomId,
        streamerName: ls.displayName,
        title: ls.title,
        category: '',
        viewerCount: ls.viewers,
        thumbnail: ls.thumbnail || undefined,
        avatar: ls.avatar || undefined,
        startTime: String(ls.startedAt || ''),
        tags: [],
    }))

    return (
        <FamilyPageShell
            sidebarOpen={sidebarOpen}
            onMenuClick={() => setSidebarOpen(true)}
            onSidebarClose={() => setSidebarOpen(false)}
        >
            <main className="flex-1 min-w-0 overflow-visible">
                <FamilyBackFab label={t('familys.backToList')} />

                <section className="relative w-full overflow-visible">
                    <div
                        className="w-full min-h-[220px] bg-cover bg-center sm:min-h-[260px] md:min-h-[290px]"
                        style={{ backgroundImage: `url("${coverUrl}")` }}
                        role="img"
                        aria-label={familyData.name}
                    />
                    <div className="relative -mt-14 overflow-visible px-4 sm:-mt-[68px] sm:px-8 md:-mt-[80px] md:px-[120px]">
                        <div className="pointer-events-auto mx-auto max-w-[1600px] overflow-visible">
                            <div className="overflow-visible rounded-2xl border border-gray-200 bg-white/90 px-4 py-3 shadow-[0_18px_45px_rgba(0,0,0,0.18)] backdrop-blur dark:border-white/10 dark:bg-[rgba(5,5,10,0.2)] dark:shadow-[0_18px_45px_rgba(0,0,0,0.45)] sm:rounded-3xl sm:px-6 sm:py-4 md:px-8 md:py-5">
                                <div className="flex flex-col overflow-visible">
                                    <div className="flex min-w-0 items-start gap-5 overflow-visible sm:gap-6">
                                        <div className="flex shrink-0 flex-col items-center">
                                            <div className="relative z-20 shrink-0">
                                                <GroupAvatar avatar={familyData.avatar} name={familyData.name} />
                                            </div>
                                        </div>
                                        <div className="min-w-0 flex flex-1 flex-col pb-0.5 sm:pb-1">
                                            <h1 className="flex flex-wrap items-center gap-1.5 text-lg font-semibold text-gray-900 dark:text-white sm:text-xl md:text-2xl">
                                                <span className="truncate">{familyData.name}</span>
                                                {familyData.isVerified ? (
                                                    <MdVerified
                                                        className="h-5 w-5 shrink-0 text-cyan-400"
                                                        title={t('catch.verified')}
                                                    />
                                                ) : null}
                                            </h1>
                                            <p className="truncate text-sm text-gray-500 dark:text-white/70">
                                                @{familyData.id}
                                            </p>
                                            {familyData.description ? (
                                                <p className="mt-2 line-clamp-3 text-sm text-gray-600 dark:text-gray-300 sm:line-clamp-none sm:whitespace-pre-wrap">
                                                    {familyData.description}
                                                </p>
                                            ) : null}
                                            <div className="mt-1.5 flex flex-wrap items-center gap-2 select-none">
                                                <span className="inline-flex items-center gap-1.5 rounded-full bg-gray-100 px-2.5 py-1 text-xs font-medium text-gray-700 dark:bg-neutral-800 dark:text-gray-200 sm:px-3 sm:py-1.5 sm:text-sm">
                                                    <FiUsers className="h-3.5 w-3.5 shrink-0 opacity-70" aria-hidden />
                                                    {t('familys.statsMembers', { value: formatViews(familyData.membersCount) })}
                                                </span>
                                                <span className="inline-flex items-center gap-1.5 rounded-full bg-gray-100 px-2.5 py-1 text-xs font-medium text-gray-700 dark:bg-neutral-800 dark:text-gray-200 sm:px-3 sm:py-1.5 sm:text-sm">
                                                    <FiUser className="h-3.5 w-3.5 shrink-0 opacity-70" aria-hidden />
                                                    {t('familys.statsArtists', { value: formatViews(familyData.artistsCount) })}
                                                </span>
                                                {liveStreams.length > 0 ? (
                                                    <span className="inline-flex items-center rounded-full bg-gray-100 px-2.5 py-1 text-xs font-medium text-gray-700 dark:bg-neutral-800 dark:text-gray-200 sm:px-3 sm:py-1.5 sm:text-sm">
                                                        {t('familys.statsLive', { value: liveStreams.length })}
                                                    </span>
                                                ) : null}
                                            </div>
                                        </div>
                                    </div>
                                    <div className="mt-4 flex shrink-0 flex-wrap items-center justify-end gap-2">
                                        {showLeaveFamilyButton ? (
                                            <button
                                                type="button"
                                                tip={t('familys.leaveFamily')}
                                                onClick={openLeaveFamilyConfirm}
                                                className={`inline-flex h-10 items-center gap-2 rounded-[12px] border border-gray-200 bg-white dark:bg-black/20 px-4 text-xs font-medium text-gray-700 transition-colors hover:bg-[rgba(145,150,161,0.1)] dark:border-white/20 dark:text-gray-100 ${tipBelowOnlyClass}`}
                                            >
                                                <FiLogOut className="h-4 w-4 shrink-0" aria-hidden />
                                                <span>{t('familys.leaveFamily')}</span>
                                            </button>
                                        ) : null}
                                        {canManageMembers ? (
                                            <button
                                                type="button"
                                                tip={t('familys.settings.button')}
                                                onClick={openSettingsModal}
                                                className={`inline-flex h-10 items-center gap-2 rounded-[12px] border border-gray-200 bg-white dark:bg-black/20 px-4 text-xs font-medium text-gray-700 transition-colors hover:bg-[rgba(145,150,161,0.1)] dark:border-white/20 dark:text-gray-100 ${tipBelowOnlyClass}`}
                                            >
                                                <FiSettings className="h-4 w-4 shrink-0" aria-hidden />
                                                <span>{t('familys.settings.button')}</span>
                                            </button>
                                        ) : null}
                                        {showApplyJoinButton ? (
                                            <button
                                                type="button"
                                                tip={applyJoinTip}
                                                disabled={applyJoinDisabled}
                                                onClick={() => void handleApplyJoin()}
                                                className={`inline-flex h-10 items-center gap-2 rounded-[12px] border border-gray-200 bg-white/90 px-4 text-xs font-medium text-gray-700 shadow-sm transition-colors hover:bg-gray-50 disabled:cursor-not-allowed disabled:opacity-60 dark:border-white/15 dark:bg-black/25 dark:text-gray-100 dark:hover:bg-white/10 ${tipBelowOnlyClass}`}
                                            >
                                                <FiUserPlus className="h-4 w-4 shrink-0" aria-hidden />
                                                <span>{applyJoinLabel}</span>
                                            </button>
                                        ) : null}
                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>
                </section>

                <section className="mt-8 px-4 pb-12 sm:mt-10 sm:px-8 md:mt-12 md:px-[120px]">
                    <div className="mx-auto max-w-[1600px]">
                        {showMemberListSection ? (
                            <FamilyMemberHub
                                liveStreams={liveStreams}
                                t={t}
                                onCheckInComingSoon={handleCheckInComingSoon}
                            />
                        ) : liveStreams.length > 0 ? (
                            <div className="mb-10 sm:mb-12">
                                <h2 className="mb-4 text-base font-semibold text-gray-900 dark:text-white sm:text-lg">
                                    {t('familys.liveStreams')}
                                </h2>
                                <div className="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3">
                                    {liveStreams.map((stream) => (
                                        <LiveCard key={stream.id} stream={stream} t={t} />
                                    ))}
                                </div>
                            </div>
                        ) : null}

                        {showMemberListSection ? (
                            <div className="overflow-visible rounded-2xl border border-gray-200 bg-white shadow-sm dark:border-white/10 dark:bg-[#0c0d0e] dark:shadow-[0_8px_30px_rgba(0,0,0,0.25)]">
                                <div className="flex items-center justify-between gap-3 border-b border-gray-100 bg-gray-50/80 px-4 py-3.5 dark:border-white/10 dark:bg-white/[0.03] sm:px-5">
                                    <h2 className="flex min-w-0 flex-1 items-center gap-2 text-base font-semibold text-gray-900 dark:text-white sm:text-lg">
                                        <FiUsers
                                            className="h-5 w-5 shrink-0 text-gray-500 dark:text-gray-400"
                                            aria-hidden
                                        />
                                        {t('familys.memberList')}
                                        <span className="inline-flex h-[1.125rem] min-w-[1.125rem] items-center justify-center rounded-full bg-white px-1.5 text-[11px] font-semibold leading-none tabular-nums text-gray-600 ring-1 ring-gray-200/80 dark:bg-neutral-800 dark:text-gray-300 dark:ring-white/10 sm:h-5 sm:min-w-[1.25rem] sm:px-2 sm:text-xs">
                                            {familyData.members.length}
                                        </span>
                                    </h2>
                                    {canReviewApplications ? (
                                        <MemberListHeaderMenu
                                            t={t}
                                            pendingCount={pendingApplications.length}
                                            onOpenReview={openApplyReviewModal}
                                            onOpenLogs={openFamilyLogModal}
                                        />
                                    ) : null}
                                </div>
                                <div className="p-3 sm:p-4 md:p-5">
                                    {familyData.members.length > 0 ? (
                                        <div className="flex w-full flex-col gap-2 overflow-visible sm:gap-3">
                                            {familyData.members.map((member) => (
                                                <MemberCard
                                                    key={member.id}
                                                    member={member}
                                                    t={t}
                                                    onSelect={openMemberViewerCard}
                                                    canManage={
                                                        canManageMembers && member.id !== currentUserId
                                                    }
                                                    showJoinAt={canViewMemberJoinTime}
                                                    onMemberAction={handleMemberAction}
                                                />
                                            ))}
                                        </div>
                                    ) : (
                                        <p className="py-6 text-center text-sm text-gray-500 dark:text-gray-400">
                                            {t('familys.emptyContent')}
                                        </p>
                                    )}
                                </div>
                            </div>
                        ) : null}

                        {!showMemberListSection && liveStreams.length === 0 ? (
                            <div className="flex flex-col items-center justify-center rounded-xl border border-dashed border-gray-200 py-16 text-center dark:border-white/10">
                                <div className="mb-3 flex h-12 w-12 items-center justify-center rounded-full bg-gray-100 dark:bg-neutral-900">
                                    <FiBox
                                        className="h-6 w-6 text-gray-400 dark:text-gray-500"
                                        aria-hidden
                                    />
                                </div>
                                <p className="text-sm text-gray-500 dark:text-gray-400">{t('familys.emptyContent')}</p>
                            </div>
                        ) : null}
                    </div>
                </section>
            </main>
            <Footer />
            {viewerCard ? (
                <ViewerCard
                    cardRef={viewerCardRef}
                    viewerCard={viewerCard}
                    viewerCardDepth={viewerCardDepth}
                    t={t}
                    onClose={closeViewerCard}
                    onBackToRoot={() => setViewerCardDepth('root')}
                    onGift={() => closeViewerCard()}
                    streamerId={undefined}
                />
            ) : null}
            <ConfirmModal
                confirmRef={confirmRef}
                isOpen={confirmModalOpen}
                title={confirmTitle}
                message={confirmMessage}
                note={confirmNote}
                confirmText={confirmConfirmText}
                onClose={closeMemberConfirm}
                onConfirm={handleConfirmMemberAction}
                confirmClosing={confirmClosing}
                confirmEntering={confirmEntering}
                severity={confirmSeverity}
                alertOnly={confirmIsAlert}
            />
            {familyData ? (
                <GroupFamilySettingsModal
                    isOpen={settingsModalOpen}
                    closing={settingsClosing}
                    entering={settingsEntering}
                    onClose={closeSettingsModal}
                    groupId={groupId}
                    initial={{
                        name: familyData.name,
                        avatar: familyData.avatar,
                        banner: familyData.banner,
                        isCanApplicapplication: familyData.isCanApplicapplication !== false,
                    }}
                    t={t}
                    onSaved={handleSettingsSaved}
                />
            ) : null}
            <GroupApplyReviewModal
                isOpen={applyReviewModalOpen}
                closing={applyReviewClosing}
                entering={applyReviewEntering}
                onClose={closeApplyReviewModal}
                applicants={pendingApplications}
                t={t}
                onReview={handleReviewApplication}
                busyUserId={reviewBusyUserId}
            />
            <GroupFamilyLogModal
                isOpen={familyLogModalOpen}
                closing={familyLogClosing}
                entering={familyLogEntering}
                onClose={closeFamilyLogModal}
                groupId={groupId}
                t={t}
            />
        </FamilyPageShell>
    )
}
