import {Stack} from 'expo-router'
import {type ReactNode} from 'react'
import {
  ScrollView,
  View,
  type ScrollViewProps,
  type TextStyle,
  type ViewProps,
} from 'react-native'
import {useSafeAreaInsets} from 'react-native-safe-area-context'

import {
  atoms as a,
  FONT_FAMILY_DISPLAY,
  tokens,
  useTheme,
  type TextStyleProp,
  type ViewStyleProp,
} from '@/sprinkles'

import {Text} from './typography'

const SCREEN_MAX_WIDTH = 800

// single source of truth for the horizontal screen gutter so every
// screen lines up regardless of which wrapper it uses
const screenGutter = a.px_2xl

const displayFont = {fontFamily: FONT_FAMILY_DISPLAY}

// shared screenOptions to apply on every Stack that shows a native
// header — keeps title typography and the minimal back button
// consistent across the app
export const stackScreenOptions = {
  headerTitleStyle: displayFont,
  headerLargeTitleStyle: displayFont,
  headerBackButtonDisplayMode: 'minimal' as const,
}

export const Layout = {
  Screen,
  LargeTitle,
  Content,
  ModalContent,
  Padded,
  Description,
  Column,
  Center,
}

function Screen({
  children,
  style,
  ...rest
}: ViewProps & {style?: ViewStyleProp}) {
  const t = useTheme()
  return (
    <View style={[a.flex_1, t.atoms.bg, style]} {...rest}>
      {children}
    </View>
  )
}

function LargeTitle({children}: {children: ReactNode}) {
  return (
    <Stack.Title large style={displayFont} largeStyle={displayFont}>
      {children}
    </Stack.Title>
  )
}

function Content({
  children,
  contentContainerStyle,
  style,
  ...rest
}: ScrollViewProps) {
  const t = useTheme()
  return (
    <ScrollView
      style={[a.flex_1, t.atoms.bg, style]}
      contentInsetAdjustmentBehavior="automatic"
      automaticallyAdjustKeyboardInsets
      keyboardShouldPersistTaps="handled"
      keyboardDismissMode="interactive"
      contentContainerStyle={[
        a.pt_lg,
        screenGutter,
        a.pb_lg,
        a.w_full,
        a.align_self_center,
        {maxWidth: SCREEN_MAX_WIDTH},
        contentContainerStyle,
      ]}
      {...rest}
    >
      {children}
    </ScrollView>
  )
}

// formSheet auto-sizes its scrollview only when it's a direct child of
// the screen (react-native-screens RNSScreenContentWrapper), so render a
// bare ScrollView with no wrapper views and fold the bottom safe-area
// inset into the content padding
function ModalContent({
  children,
  contentContainerStyle,
  style,
  ...rest
}: ScrollViewProps) {
  const t = useTheme()
  const insets = useSafeAreaInsets()
  return (
    <ScrollView
      style={[a.flex_1, t.atoms.bg, style]}
      contentInsetAdjustmentBehavior="automatic"
      automaticallyAdjustKeyboardInsets
      keyboardShouldPersistTaps="handled"
      keyboardDismissMode="interactive"
      contentContainerStyle={[
        a.py_2xl,
        screenGutter,
        {paddingBottom: insets.bottom + tokens.space._2xl},
        contentContainerStyle,
      ]}
      {...rest}
    >
      {children}
    </ScrollView>
  )
}

// horizontal screen gutter for screens that build their own body
// (keyboard avoidance, centering, composer bars) instead of using
// Content/ModalContent
function Padded({
  children,
  style,
}: {
  children: ReactNode
  style?: ViewStyleProp
}) {
  return <View style={[screenGutter, style]}>{children}</View>
}

function Description({
  children,
  style,
}: {
  children: ReactNode
  style?: TextStyleProp
}) {
  const t = useTheme()
  return (
    <Text
      style={[
        a.text_md,
        a.leading_normal,
        t.atoms.text_contrast_medium,
        // negative margin cancels Layout.Content's paddingTop so the
        // description sits flush below the large title; paddingBottom
        // is _2xl rather than lg to visually match the gap an iOS large
        // title leaves below itself (which is larger than text leading)
        {
          marginTop: -tokens.space.lg,
          paddingBottom: tokens.space._2xl,
        },
        style as TextStyle,
      ]}
    >
      {children}
    </Text>
  )
}

function Column({
  children,
  style,
}: {
  children: ReactNode
  style?: ViewStyleProp
}) {
  return <View style={[a.gap_2xl, style]}>{children}</View>
}

function Center({
  children,
  style,
}: {
  children: ReactNode
  style?: ViewStyleProp
}) {
  return (
    <View style={[a.flex_1, a.justify_center, a.align_center, style]}>
      {children}
    </View>
  )
}
