'use client'

import Image from 'next/image'
import Link from 'next/link'
import Lottie from 'lottie-react'
import { useEffect, useState } from 'react'
import { FaUser } from 'react-icons/fa6'
import { resolveAvatarFrameAssetUrl } from '@/lib/avatarFrames/resolveUrl'
import type { AvatarFramePayload } from '@/lib/avatarFrames/types'
import { hasValidImageSrc, isLottieAnimationData } from '@/lib/media/mediaGuards'

export const AVATAR_FRAME_AVATAR_PX = 116
export const AVATAR_FRAME_RING_PX = 166

export type AvatarWithFrameSize = 'default' | 'md' | 'sm'

export const AVATAR_FRAME_SIZE_PRESETS: Record<
    AvatarWithFrameSize,
    { avatar: number; ring: number; placeholder: number }
> = {
    default: { avatar: AVATAR_FRAME_AVATAR_PX, ring: AVATAR_FRAME_RING_PX, placeholder: 52 },
    /** 個人頁橫幅等中型展示 */
    md: { avatar: 96, ring: 138, placeholder: 44 },
    sm: { avatar: 72, ring: 102, placeholder: 32 },
}

export function getAvatarFrameSizePreset(size: AvatarWithFrameSize = 'default') {
    return AVATAR_FRAME_SIZE_PRESETS[size]
}

export const AVATAR_FRAME_RING_PX_SM = AVATAR_FRAME_SIZE_PRESETS.sm.ring

type AvatarFrameDimensions = (typeof AVATAR_FRAME_SIZE_PRESETS)['default']

export type AvatarWithFrameProps = {
    avatarSrc?: string | null
    alt?: string
    frame?: AvatarFramePayload | null
    className?: string
    href?: string
    placeholderIconClassName?: string
    ringClassName?: string
    size?: AvatarWithFrameSize
}

function AvatarCore({
    avatarSrc,
    alt,
    placeholderIconClassName,
    dimensions,
}: {
    avatarSrc?: string | null
    alt: string
    placeholderIconClassName?: string
    dimensions: AvatarFrameDimensions
}) {
    const { avatar: avatarPx, placeholder: placeholderPx } = dimensions
    return (
        <div
            className="relative shrink-0 overflow-hidden rounded-full bg-gray-100 dark:bg-neutral-800"
            style={{ width: avatarPx, height: avatarPx }}
        >
            {hasValidImageSrc(avatarSrc) ? (
                <Image
                    src={avatarSrc}
                    alt={alt}
                    width={avatarPx}
                    height={avatarPx}
                    className="h-full w-full object-cover"
                    sizes={`${avatarPx}px`}
                    unoptimized
                />
            ) : (
                <span className="flex h-full w-full items-center justify-center text-gray-400 dark:text-gray-500">
                    <FaUser
                        className={placeholderIconClassName}
                        style={
                            placeholderIconClassName
                                ? undefined
                                : { width: placeholderPx, height: placeholderPx }
                        }
                        aria-hidden
                    />
                </span>
            )}
        </div>
    )
}

function AvatarFrameRing({
    frame,
    className,
    dimensions,
}: {
    frame: AvatarFramePayload
    className?: string
    dimensions: AvatarFrameDimensions
}) {
    const [lottieData, setLottieData] = useState<object | null>(null)
    const frameSrc = resolveAvatarFrameAssetUrl(frame.image)
    const { ring: ringPx } = dimensions

    useEffect(() => {
        if (frame.type !== 'LOTTIE') {
            setLottieData(null)
            return
        }
        if (!frameSrc) return
        let cancelled = false
        const load = async () => {
            try {
                const res = await fetch(frameSrc)
                if (!res.ok) return
                const data = await res.json()
                if (!cancelled && isLottieAnimationData(data)) setLottieData(data)
            } catch {
                // ignore
            }
        }
        void load()
        return () => {
            cancelled = true
        }
    }, [frame.id, frameSrc, frame.type])

    const showLottie = frame.type === 'LOTTIE' && isLottieAnimationData(lottieData)
    const showImg = frame.type === 'IMG' && hasValidImageSrc(frameSrc)

    return (
        <div
            className={`pointer-events-none absolute left-1/2 top-1/2 z-10 -translate-x-1/2 -translate-y-[56%] ${className ?? ''}`}
            style={{ width: ringPx, height: ringPx }}
            aria-hidden
        >
            <div className="relative h-full w-full">
                {showLottie ? (
                    <Lottie animationData={lottieData} loop autoplay className="h-full w-full" />
                ) : null}
                {showImg ? (
                    <Image
                        src={frameSrc}
                        alt=""
                        width={ringPx}
                        height={ringPx}
                        className="h-full w-full object-contain"
                        sizes={`${ringPx}px`}
                        unoptimized
                    />
                ) : null}
            </div>
        </div>
    )
}

function AvatarWithFrameInner({
    avatarSrc,
    alt = '',
    frame,
    className = '',
    placeholderIconClassName,
    ringClassName = '',
    size = 'default',
}: AvatarWithFrameProps) {
    const hasFrame = Boolean(frame?.image)
    const dimensions = getAvatarFrameSizePreset(size)
    const { ring: ringPx } = dimensions

    return (
        <div
            className={`relative shrink-0 overflow-visible ${className}`}
            style={{ width: ringPx, height: ringPx, minWidth: ringPx, minHeight: ringPx }}
        >
            <div className="absolute inset-0 flex items-center justify-center overflow-visible">
                <AvatarCore
                    avatarSrc={avatarSrc}
                    alt={alt}
                    placeholderIconClassName={placeholderIconClassName}
                    dimensions={dimensions}
                />
                {hasFrame && frame ? (
                    <AvatarFrameRing key={frame.id} frame={frame} className={ringClassName} dimensions={dimensions} />
                ) : null}
            </div>
        </div>
    )
}

export default function AvatarWithFrame(props: AvatarWithFrameProps) {
    const { href, ...rest } = props
    const inner = <AvatarWithFrameInner {...rest} />

    if (href) {
        return (
            <Link href={href} className="block shrink-0">
                {inner}
            </Link>
        )
    }

    return inner
}
