import {Image} from 'expo-image'
import {View} from 'react-native'

import {Text} from '@/components/ui/typography'
import {useTheme, type Palette} from '@/sprinkles'

const DISC_COLORS: (keyof Palette)[] = [
  'primary_500',
  'positive_500',
  'negative_500',
]

// stable per-handle disc color for the photo-less fallback
const discColor = (palette: Palette, handle: string) => {
  const sum = [...handle].reduce(
    (acc, ch) => acc + ch.charCodeAt(0),
    0,
  )
  return palette[DISC_COLORS[sum % DISC_COLORS.length]!]
}

type AvatarProps = {
  handle: string
  uri?: string | null
  size?: number
  borderColor?: string
}

export const Avatar = ({
  handle,
  uri,
  size = 40,
  borderColor,
}: AvatarProps) => {
  const t = useTheme()
  const base = {
    width: size,
    height: size,
    borderRadius: size / 2,
    ...(borderColor ? {borderWidth: 1.5, borderColor} : null),
  }

  if (uri)
    return (
      <Image
        source={{uri}}
        style={base}
        contentFit="cover"
        transition={120}
        cachePolicy="memory-disk"
        accessibilityLabel={`@${handle}`}
      />
    )

  // setting lineHeight to the full circle height (not fontSize) lets the
  // single glyph center on its own metrics instead of clipping in a tight box
  const fontSize = Math.round(size * 0.45)

  return (
    <View
      accessibilityLabel={`@${handle}`}
      style={{
        ...base,
        backgroundColor: discColor(t.palette, handle),
        alignItems: 'center',
        justifyContent: 'center',
      }}
    >
      <Text
        style={{
          color: t.palette.white,
          fontWeight: '600',
          fontSize,
          lineHeight: size,
          textAlign: 'center',
        }}
      >
        {handle[0]?.toUpperCase()}
      </Text>
    </View>
  )
}
