import React from 'react'
import type { TamaguiElement } from '@tamagui/core'
import { useConfiguration } from '@tamagui/core'
import { useConstant } from '@tamagui/use-constant'
import { useControllableState } from '@tamagui/use-controllable-state'

import type { ScrollBridge, SheetProps } from './types'
import type { SheetOpenState } from './useSheetOpenState'

export type SheetContextValue = ReturnType<typeof useSheetProviderProps> & {
  setHasScrollView: (val: boolean) => void
}

export function useSheetProviderProps(
  props: SheetProps,
  state: SheetOpenState,
  options: {
    onOverlayComponent?: (comp: any) => void
  } = {}
) {
  const handleRef = React.useRef<TamaguiElement>(null)
  const contentRef = React.useRef<TamaguiElement>(null)
  const [frameSize, setFrameSize] = React.useState<number>(0)
  const [maxContentSize, setMaxContentSize] = React.useState<number>(0)
  const snapPointsMode = props.snapPointsMode ?? 'percent'
  const snapPointsProp: (string | number)[] =
    props.snapPoints ??
    (snapPointsMode === 'percent'
      ? [80]
      : snapPointsMode === 'constant'
        ? [256]
        : ['fit'])
  const hasFit = snapPointsProp[0] === 'fit'

  const snapPoints = React.useMemo(
    () => (props.dismissOnSnapToBottom ? [...snapPointsProp, 0] : snapPointsProp),

    [JSON.stringify(snapPointsProp), props.dismissOnSnapToBottom]
  )

  // lets set -1 to be always the "open = false" position
  const [position_, setPositionImmediate] = useControllableState({
    prop: props.position,
    defaultProp: props.defaultPosition || (state.open ? 0 : -1),
    onChange: props.onPositionChange,
    strategy: 'most-recent-wins',
  })

  const position = state.open === false ? -1 : position_

  const { open } = state

  const setPosition = React.useCallback(
    (next: number) => {
      // close on dismissOnSnapToBottom (and set position so it animates)
      if (props.dismissOnSnapToBottom && next === snapPoints.length - 1) {
        state.setOpen(false)
      } else {
        setPositionImmediate(next)
      }
    },
    [props.dismissOnSnapToBottom, snapPoints.length, setPositionImmediate, state.setOpen]
  )

  if (process.env.NODE_ENV === 'development') {
    if (
      snapPointsMode === 'mixed' &&
      snapPoints.some((p) => {
        if (typeof p === 'string') {
          if (p === 'fit') {
            return false
          }
          if (p.endsWith('%')) {
            const n = Number(p.slice(0, -1))
            return n < 0 || n > 100
          }
          return true
        }
        return typeof p !== 'number' || p < 0
      })
    ) {
      console.warn(
        '⚠️ Invalid snapPoint given, snapPoints must be positive numeric values, string percentages between 0-100%, or "fit" when snapPointsMode is mixed'
      )
    }
    if (snapPointsMode === 'mixed' && snapPoints.indexOf('fit') > 0) {
      console.warn(
        '⚠️ Invalid snapPoint given, "fit" must be the first/largest snap point when snapPointsMode is mixed'
      )
    }
    if (
      snapPointsMode === 'fit' &&
      (snapPoints.length !== (props.dismissOnSnapToBottom ? 2 : 1) ||
        snapPoints[0] !== 'fit')
    ) {
      console.warn(
        '⚠️ Invalid snapPoint given, there are no snap points when snapPointsMode is fit'
      )
    }
    if (
      snapPointsMode === 'constant' &&
      snapPoints.some((p) => typeof p !== 'number' || p < 0)
    ) {
      console.warn(
        '⚠️ Invalid snapPoint given, snapPoints must be positive numeric values when snapPointsMode is constant'
      )
    }
    if (
      snapPointsMode === 'percent' &&
      snapPoints.some((p) => typeof p !== 'number' || p < 0 || p > 100)
    ) {
      console.warn(
        '⚠️ Invalid snapPoint given, snapPoints must be numeric values between 0 and 100 when snapPointsMode is percent'
      )
    }
  }

  // reset position to fully open on re-open after dismissOnSnapToBottom
  if (open && props.dismissOnSnapToBottom && position === snapPoints.length - 1) {
    setPositionImmediate(0)
  }

  // open must set position
  const shouldSetPositionOpen = open && position < 0
  React.useEffect(() => {
    if (shouldSetPositionOpen) {
      setPosition(0)
    }
  }, [setPosition, shouldSetPositionOpen])

  const { animationDriver } = useConfiguration()
  if (!animationDriver) {
    throw new Error(
      process.env.NODE_ENV === 'production'
        ? `❌ 008`
        : 'Must set animations in tamagui.config.ts'
    )
  }

  const scrollBridge = useConstant<ScrollBridge>(() => {
    const parentDragListeners = new Set<Function>()

    const bridge: ScrollBridge = {
      hasScrollableContent: false,
      enabled: false,
      y: 0,
      paneY: 0,
      paneMinY: 0,
      scrollStartY: -1,
      drag: () => {},
      release: () => {},
      scrollLock: false,
      isParentDragging: false,
      onParentDragging: (cb) => {
        parentDragListeners.add(cb)
        return () => {
          parentDragListeners.delete(cb)
        }
      },
      setParentDragging: (val) => {
        if (val !== bridge.isParentDragging) {
          bridge.isParentDragging = val
          parentDragListeners.forEach((cb) => cb(val))
        }
      },
    }

    return bridge
  })

  // Handle both new disableRemoveScroll and deprecated forceRemoveScrollEnabled
  let disableRemoveScroll: boolean | undefined
  if (props.disableRemoveScroll !== undefined) {
    // New prop: disableRemoveScroll={true} means RemoveScroll is disabled
    disableRemoveScroll = props.disableRemoveScroll || !open || !props.modal
  } else if (props.forceRemoveScrollEnabled !== undefined) {
    // Deprecated prop: forceRemoveScrollEnabled can override the default
    if (process.env.NODE_ENV === 'development') {
      console.warn(
        '[Sheet] forceRemoveScrollEnabled is deprecated. Use disableRemoveScroll instead.'
      )
    }
    disableRemoveScroll = !props.forceRemoveScrollEnabled
  } else {
    // Default: disabled when not open or not modal
    disableRemoveScroll = !open || !props.modal
  }

  const maxSnapPoint = snapPoints[0]
  const screenSize =
    snapPointsMode === 'percent'
      ? frameSize / ((typeof maxSnapPoint === 'number' ? maxSnapPoint : 100) / 100)
      : maxContentSize

  const providerProps = {
    screenSize,
    maxSnapPoint,
    disableRemoveScroll,
    scrollBridge,
    modal: !!props.modal,
    open: state.open,
    setOpen: state.setOpen,
    hidden: !!state.isHidden,
    contentRef,
    handleRef,
    frameSize,
    setFrameSize,
    dismissOnOverlayPress: props.dismissOnOverlayPress ?? true,
    dismissOnSnapToBottom: props.dismissOnSnapToBottom ?? false,
    onOverlayComponent: options.onOverlayComponent,
    scope: props.__scopeSheet,
    hasFit,
    position,
    snapPoints,
    snapPointsMode,
    setMaxContentSize,
    setPosition,
    setPositionImmediate,
    onlyShowFrame: false,
  }

  return providerProps
}
