import {useEffect} from 'react'
import {View} from 'react-native'
import Animated, {
  Easing,
  type SharedValue,
  useAnimatedStyle,
  useSharedValue,
  withDelay,
  withTiming,
} from 'react-native-reanimated'
import {moderateProfile} from '@atproto/api'

import {useMaybeProfileShadow} from '#/state/cache/profile-shadow'
import {useEnableSquareAvatars} from '#/state/preferences/enable-square-avatars'
import {useModerationOpts} from '#/state/preferences/moderation-opts'
import {useSession} from '#/state/session'
import {UserAvatar} from '#/view/com/util/UserAvatar'
import {atoms as a, useTheme} from '#/alf'
import {Person_Filled_Corner2_Rounded as PersonIcon} from '#/components/icons/Person'
import type * as bsky from '#/types/bsky'

type Layout = {
  size: number
  x: number
  y: number
  zIndex?: number
  border?: boolean
}

export function AvatarBubbles({
  animate = false,
  profiles: allProfiles,
  self = false,
  size = 120,
}: {
  animate?: boolean
  profiles: (bsky.profile.AnyProfileView | undefined)[]
  /**
   * By default, when there are more than 2 profiles, the current user is
   * filtered out (so you don't see yourself among your own group's members).
   * Set this to `true` for cases where every passed profile should appear,
   * e.g. an invite preview where the owner is meaningful regardless of viewer.
   */
  self?: boolean
  size?: number
}) {
  const {currentAccount} = useSession()
  const profiles =
    !self && allProfiles.length > 2
      ? allProfiles.filter(p => !p || p.did !== currentAccount?.did)
      : allProfiles

  const scale = size / 120
  const marginOffset = size < 120 ? -2 : 0

  const initialValue = animate ? 0 : 1
  const p0 = useSharedValue(initialValue)
  const p1 = useSharedValue(initialValue)
  const p2 = useSharedValue(initialValue)
  const p3 = useSharedValue(initialValue)

  useEffect(() => {
    if (!animate) return
    const animateBubble = (p: SharedValue<number>, i: number) => {
      p.set(0)
      p.set(() =>
        withDelay(
          500 + i * 100,
          withTiming(1, {
            duration: 250,
            easing: Easing.out(Easing.back(1.75)),
          }),
        ),
      )
    }
    animateBubble(p0, 0)
    animateBubble(p1, 1)
    animateBubble(p2, 2)
    animateBubble(p3, 3)
  }, [animate, p0, p1, p2, p3])

  const scales = [p0, p1, p2, p3]
  const layouts = getLayouts(profiles.length)

  return (
    <Animated.View style={[a.p_2xs, {height: size, width: size}]}>
      <View
        style={{
          marginTop: marginOffset,
          marginLeft: marginOffset,
          transform: [{scale}],
          transformOrigin: 'top left',
        }}>
        {layouts.map((layout, i) => (
          <AvatarBubble
            key={i}
            profile={profiles[i]}
            scale={scales[i]}
            size={layout.size}
            x={layout.x}
            y={layout.y}
            zIndex={layout.zIndex}
            includeProfileBorder={layout.border}
          />
        ))}
      </View>
    </Animated.View>
  )
}

function AvatarBubble({
  profile: profileUnshadowed,
  scale,
  size,
  x,
  y,
  zIndex,
  includeProfileBorder,
}: {
  profile?: bsky.profile.AnyProfileView
  scale: SharedValue<number>
  size: number
  x: number
  y: number
  zIndex?: number
  includeProfileBorder?: boolean
}) {
  const t = useTheme()
  const enableSquareAvatars = useEnableSquareAvatars()
  const borderRadius = avatarBorderRadius(size, !!enableSquareAvatars)
  const animatedStyle = useAnimatedStyle(() => ({
    transform: [{translateX: x}, {translateY: y}, {scale: scale.get()}],
  }))

  const profile = useMaybeProfileShadow(profileUnshadowed)
  const moderationOpts = useModerationOpts()

  return (
    <Animated.View
      style={[
        a.absolute,
        {borderRadius},
        a.flex_grow_0,
        includeProfileBorder && {
          borderColor: t.atoms.text_inverted.color,
          borderWidth: 2,
        },
        zIndex != null && {zIndex},
        animatedStyle,
      ]}>
      {profile && moderationOpts ? (
        <UserAvatar
          avatar={profile.avatar}
          size={size}
          type="user"
          hideLiveBadge
          noBorder
          moderation={moderateProfile(profile, moderationOpts).ui('avatar')}
        />
      ) : (
        <AvatarPlaceholder size={size} />
      )}
    </Animated.View>
  )
}

function AvatarPlaceholder({size}: {size: number}) {
  const t = useTheme()
  const enableSquareAvatars = useEnableSquareAvatars()
  const borderRadius = avatarBorderRadius(size, !!enableSquareAvatars)

  return (
    <View
      style={[
        a.align_center,
        a.justify_center,
        {borderRadius, width: size, height: size},
        t.atoms.bg_contrast_200,
      ]}>
      <PersonIcon
        width={size * 0.5}
        height={size * 0.5}
        fill={t.atoms.text_inverted.color}
      />
    </View>
  )
}

function avatarBorderRadius(size: number, square: boolean) {
  if (square) {
    return size > 32 ? 8 : 3
  }
  return Math.floor(size / 2)
}

function getLayouts(count: number): Layout[] {
  if (count === 3) {
    return [
      {size: 68, x: -2, y: -2},
      {size: 56, x: 38, y: 62},
      {size: 46, x: 71, y: 18},
    ]
  }
  if (count >= 4) {
    return [
      {size: 68, x: -2, y: -2},
      {size: 56, x: 60, y: 49},
      {size: 42, x: 14, y: 74},
      {size: 32, x: 72, y: 9},
    ]
  }
  return [
    {size: 76, x: -2, y: -2, zIndex: 20, border: true},
    {size: 76, x: 42, y: 42, zIndex: 10, border: true},
  ]
}
