import { useMemo, useState } from 'react'
import { StyleSheet, View } from 'react-native'
import { runOnJS, type SharedValue, useAnimatedReaction } from 'react-native-reanimated'
import { Pagination } from 'react-native-reanimated-carousel'
import { MediaBadge } from 'src/components/ui/MediaBadge'

// Album slide indicator, overlaid on the media itself. Two presentations:
//   - 2..8 slides → a centered dot row at the media's bottom edge (the
//     Instagram convention); the dots double as the "there are N images" cue.
//   - 9+ slides   → a "k / N" count pill top-right instead. A 9-dot row reads
//     as visual noise (Pixelfed caps albums at 25 slides), and the pill is
//     the only thing that conveys position once the dots stop being countable.
// Nothing renders for a single attachment.
//
// COLOURS HERE ARE INTENTIONALLY NOT THEMED. The indicator sits on arbitrary
// user photos, so it needs fixed light-on-dark contrast regardless of the app
// theme — the same documented overlay exception MediaBadge relies on (idle
// dots at half-opacity white, active dot solid white, on a low-opacity dark
// scrim so they read on bright images). A future "drop all hex / re-tokenise"
// sweep must skip this surface.
const DOT_SIZE = 7
const DOT_INSET = 10
const MAX_DOTS = 8
const IDLE_DOT = 'rgba(255,255,255,0.55)'
const ACTIVE_DOT = '#fff'
const DOT_SCRIM = 'rgba(0,0,0,0.35)'

type Props = {
  count: number
  progress: SharedValue<number>
}

export default function MediaPagination({ count, progress }: Props) {
  if (count <= 1) return null
  if (count > MAX_DOTS) return <CountPill count={count} progress={progress} />
  return <DotRow count={count} progress={progress} />
}

function DotRow({ count, progress }: Props) {
  // Pagination.Basic only consumes `data.length` + each `index`; a length-N
  // array of throwaway numbers is all it needs to draw N dots, so we never
  // thread the real attachments down here.
  const dots = useMemo(() => Array.from({ length: count }, (_, i) => i), [count])
  return (
    <View pointerEvents="none" style={styles.dotWrap}>
      <Pagination.Basic
        progress={progress}
        data={dots}
        size={DOT_SIZE}
        dotStyle={{ backgroundColor: IDLE_DOT, borderRadius: 50 }}
        activeDotStyle={{ backgroundColor: ACTIVE_DOT, borderRadius: 50 }}
        containerStyle={styles.dotRow}
      />
    </View>
  )
}

function CountPill({ count, progress }: Props) {
  const [index, setIndex] = useState(0)
  // Snap-granularity update: the prepare worklet rounds `progress` every frame
  // on the UI thread (a cheap clamp), but the reaction — and the JS setState —
  // only fires when the integer slide index actually changes, i.e. on swipe
  // snap. No per-frame JS bridge, so the feed-scroll cost stays flat.
  useAnimatedReaction(
    () => Math.min(count - 1, Math.max(0, Math.round(progress.value))),
    (current, previous) => {
      if (current !== previous) runOnJS(setIndex)(current)
    },
    [count]
  )
  return (
    <View pointerEvents="none" style={styles.fill}>
      <MediaBadge text={`${index + 1} / ${count}`} corner="topRight" />
    </View>
  )
}

const styles = StyleSheet.create({
  // Full-bleed, non-interactive layer so MediaBadge's absolute corner anchor
  // resolves against the media box and taps still reach the carousel beneath.
  fill: { position: 'absolute', top: 0, left: 0, right: 0, bottom: 0, zIndex: 10 },
  // Bottom-center band; `alignItems:center` centers the dot row over the image.
  dotWrap: {
    position: 'absolute',
    left: 0,
    right: 0,
    bottom: DOT_INSET,
    alignItems: 'center',
    zIndex: 10,
  },
  // The scrim/halo lives on the row (not via `opacity`, which would dim the
  // dots too) so the white dots stay legible on bright photos.
  dotRow: {
    gap: 5,
    paddingHorizontal: 7,
    paddingVertical: 5,
    borderRadius: 12,
    backgroundColor: DOT_SCRIM,
  },
})
