import type React from 'react'
import { Platform, StyleSheet } from 'react-native'
import { useSafeAreaInsets } from 'react-native-safe-area-context'
import { GlassSurface } from 'src/components/common/GlassSurface'
import { BAR_HEIGHT } from 'src/components/menu/MenuBar'
import { ScrollView, Text, useTheme, View } from 'tamagui'
import { ScreenFadeEdges } from './ScreenFadeEdges'
import { type ScreenScrollInsets, useScreenScrollInsets } from './useScreenScrollInsets'

// Sticky-header content height. Matches BAR_HEIGHT so the sticky page
// header and the floating menu bar share a visual rhythm.
const HEADER_CONTENT_HEIGHT = BAR_HEIGHT

// Props a scroll-capable child (FlashList, Animated.FlashList, ScrollView)
// must spread onto its underlying scroller so content lines up with the
// safe-area / sticky-header geometry that the container computed.
export type ScreenScrollChildProps = {
  contentInsetAdjustmentBehavior: 'never'
  contentInset: { top: number; bottom: number }
  scrollIndicatorInsets: { top: number; bottom: number }
  contentContainerStyle: { paddingTop: number; paddingBottom: number }
  // Raw reserves exposed for consumers that can't take the spread — most
  // importantly `<RefreshControl progressViewOffset={scrollProps.topInset} />`.
  topInset: number
  bottomInset: number
}

type ChildrenRenderFn = (props: ScreenScrollChildProps) => React.ReactElement

type CommonProps = {
  // Rendered as a sticky bar absolutely positioned over the scroller. A
  // string is rendered with the default title treatment; anything else is
  // rendered as-is inside a height-constrained row.
  header?: React.ReactNode
  // iOS uses a neutral-tinted BlurView backdrop by default; set to `false`
  // to get a solid `$background` sticky bar (handy when the header needs a
  // hard top edge against a busy surface underneath).
  headerBlur?: boolean
  // Overrides the default sticky-header height. Used when the header slot
  // embeds taller chrome (stacked title + segmented control, etc.).
  headerHeight?: number
}

export type ScreenScrollContainerProps =
  | ({ variant: 'scroll'; children: React.ReactNode } & CommonProps)
  | ({
      variant: 'flashlist' | 'animated-flashlist'
      children: ChildrenRenderFn
    } & CommonProps)

// One page wrapper, one rule: content begins below the top inset, scrolls
// under the status-bar blur on iOS (solid $background chrome on Android),
// and reserves room at the bottom for the floating menu + tab strip.
//
// For static content (settings pages) pass `variant='scroll'` and render
// children as JSX — the container owns a ScrollView.
// For list-backed screens (feeds, grids) pass `variant='flashlist'` (or
// `'animated-flashlist'` for lists wrapped with Animated.createAnimatedComponent)
// and render children as a function — the container hands back the
// contentInset / contentContainerStyle props the list should spread onto
// itself. This keeps list-specific props (`data`, `renderItem`, `ref`,
// animated scroll handlers, etc.) out of the container's API surface.
export function ScreenScrollContainer(props: ScreenScrollContainerProps) {
  const { header, headerBlur = true, headerHeight: headerHeightProp } = props
  const hasHeader = header != null
  const headerContentHeight = headerHeightProp ?? HEADER_CONTENT_HEIGHT
  const effectiveHeaderHeight = hasHeader ? headerContentHeight : 0

  const insets = useSafeAreaInsets()
  const scrollInsets = useScreenScrollInsets({
    headerHeight: effectiveHeaderHeight,
  })

  const childProps: ScreenScrollChildProps = {
    contentInsetAdjustmentBehavior: scrollInsets.contentInsetAdjustmentBehavior,
    contentInset: scrollInsets.contentInset,
    scrollIndicatorInsets: scrollInsets.scrollIndicatorInsets,
    contentContainerStyle: scrollInsets.contentContainerStyle,
    topInset: scrollInsets.topInset,
    bottomInset: scrollInsets.bottomInset,
  }

  return (
    <View flex={1} backgroundColor="$background">
      {props.variant === 'scroll' ? (
        <ScrollView
          flex={1}
          showsVerticalScrollIndicator={false}
          contentInsetAdjustmentBehavior={childProps.contentInsetAdjustmentBehavior}
          contentInset={childProps.contentInset}
          scrollIndicatorInsets={childProps.scrollIndicatorInsets}
          contentContainerStyle={childProps.contentContainerStyle}
        >
          {props.children}
        </ScrollView>
      ) : (
        props.children(childProps)
      )}

      <ScreenFadeEdges />

      {hasHeader ? (
        <StickyHeader
          topInset={insets.top}
          contentHeight={headerContentHeight}
          blur={headerBlur}
        >
          {header}
        </StickyHeader>
      ) : null}
    </View>
  )
}

export type { ScreenScrollInsets }
// Re-export for consumers that want to compute their own scroll props
// (e.g. a screen that embeds two scrollers side-by-side under one header).
export { useScreenScrollInsets }

function StickyHeader({
  topInset,
  contentHeight,
  blur,
  children,
}: {
  topInset: number
  contentHeight: number
  blur: boolean
  children: React.ReactNode
}) {
  const theme = useTheme()
  // Android: solid $background chrome. iOS with blur=true: GlassSurface draws
  // a neutral frosted backdrop. iOS with blur=false: solid $background — the
  // same look as Android but still respects the safe-area top inset so the
  // status bar text stays legible.
  const useSolidBackground = Platform.OS === 'android' || !blur
  return (
    <View
      position="absolute"
      top={0}
      left={0}
      right={0}
      height={topInset + contentHeight}
      pointerEvents="box-none"
      overflow="hidden"
    >
      {useSolidBackground ? (
        <View
          style={[
            StyleSheet.absoluteFill,
            { backgroundColor: theme.background.val as string },
          ]}
          pointerEvents="none"
        />
      ) : (
        <GlassSurface kind="translucent" androidBlur="solid" />
      )}
      <View
        flex={1}
        paddingTop={topInset}
        paddingHorizontal="$5"
        flexDirection="row"
        alignItems="center"
      >
        {typeof children === 'string' ? (
          <Text fontSize="$7" fontWeight="700" allowFontScaling={false} color="$color">
            {children}
          </Text>
        ) : (
          children
        )}
      </View>
    </View>
  )
}
