import { ReactNode } from "react"
import {
  Modal as RNModal,
  ModalProps as RNModalProps,
  Platform,
  Pressable,
  StyleProp,
  TextStyle,
  View,
  ViewStyle,
} from "react-native"
import { KeyboardAwareScrollView } from "react-native-keyboard-controller"
import { useSafeAreaInsets } from "react-native-safe-area-context"

import { useAppTheme } from "@/theme/context"
import type { ThemedStyle } from "@/theme/types"
import { s } from "@/utils/responsive"

import { Button, ButtonProps } from "./Button"
import { Icon } from "./Icon"
import { Text, TextProps } from "./Text"

type Presets = "center" | "bottom" | "fullscreen"

export interface ModalProps extends Omit<RNModalProps, "children"> {
  /**
   * Whether the modal is visible.
   */
  visible: boolean
  /**
   * Callback when the modal is requested to close.
   */
  onClose: () => void
  /**
   * Modal position preset.
   * - `center`: Centered dialog (default)
   * - `bottom`: Bottom sheet style, slides up from bottom
   * - `fullscreen`: Full screen modal
   * @default "center"
   */
  preset?: Presets
  /**
   * Title text which is looked up via i18n.
   */
  titleTx?: TextProps["tx"]
  /**
   * Title text to display if not using `titleTx`.
   */
  title?: string
  /**
   * Optional title options to pass to i18n.
   */
  titleTxOptions?: TextProps["txOptions"]
  /**
   * Style overrides for the title text.
   */
  titleStyle?: StyleProp<TextStyle>
  /**
   * Whether to show the close button in the header.
   * @default true
   */
  showCloseButton?: boolean
  /**
   * Whether to close the modal when pressing the overlay.
   * @default true
   */
  closeOnOverlayPress?: boolean
  /**
   * The content to display inside the modal.
   */
  children?: ReactNode
  /**
   * Style overrides for the overlay.
   */
  overlayStyle?: StyleProp<ViewStyle>
  /**
   * Style overrides for the content container.
   */
  contentStyle?: StyleProp<ViewStyle>
  /**
   * Props for the confirm button (right button).
   * If provided, the footer buttons will be shown.
   */
  confirmButtonProps?: ButtonProps
  /**
   * Props for the cancel button (left button).
   * If provided along with confirmButtonProps, both buttons will be shown.
   */
  cancelButtonProps?: ButtonProps
  /**
   * Custom footer component.
   * Overrides confirmButtonProps and cancelButtonProps.
   */
  FooterComponent?: ReactNode
  /**
   * Animation type for the modal.
   * Defaults based on preset: "fade" for center, "slide" for bottom/fullscreen
   */
  animationType?: "none" | "slide" | "fade"
  /**
   * Maximum width of the modal content (only applies to "center" preset).
   * @default 400
   */
  maxWidth?: number
}

/**
 * A reusable modal component with overlay, title, close button, and footer actions.
 * Supports theming, internationalization, and multiple position presets.
 * @param {ModalProps} props - The props for the `Modal` component.
 * @returns {JSX.Element} The rendered `Modal` component.
 * @example
 * // Center modal (default)
 * <Modal
 *   visible={isVisible}
 *   onClose={() => setIsVisible(false)}
 *   titleTx="common:confirm"
 * >
 *   <Text tx="modal:content" />
 * </Modal>
 *
 * @example
 * // Bottom sheet modal
 * <Modal
 *   visible={isVisible}
 *   onClose={() => setIsVisible(false)}
 *   preset="bottom"
 *   titleTx="profile:editProfile"
 * >
 *   <TextField ... />
 * </Modal>
 */
export function Modal(props: ModalProps) {
  const {
    visible,
    onClose,
    preset = "center",
    titleTx,
    title,
    titleTxOptions,
    titleStyle: $titleStyleOverride,
    showCloseButton = true,
    closeOnOverlayPress = true,
    children,
    overlayStyle: $overlayStyleOverride,
    contentStyle: $contentStyleOverride,
    confirmButtonProps,
    cancelButtonProps,
    FooterComponent,
    animationType,
    maxWidth = s(400),
    ...rest
  } = props

  const { themed, theme } = useAppTheme()
  const insets = useSafeAreaInsets()

  const hasTitleArea = !!(titleTx || title || showCloseButton)
  const hasFooter = !!(FooterComponent || confirmButtonProps)

  // Determine animation type based on preset
  const resolvedAnimationType = animationType ?? (preset === "center" ? "fade" : "slide")

  // Build overlay style based on preset
  const $overlayStyle: StyleProp<ViewStyle> = [
    themed($overlayBase),
    preset === "center" && themed($overlayCenter),
    preset === "bottom" && $overlayBottom,
    preset === "fullscreen" && $overlayFullscreen,
    $overlayStyleOverride,
  ]

  // Build content container style based on preset
  const $contentContainerStyle: StyleProp<ViewStyle> = [
    themed($contentBase),
    preset === "center" && [themed($contentCenter), { maxWidth }],
    preset === "bottom" && [themed($contentBottom), { paddingBottom: insets.bottom || s(24) }],
    preset === "fullscreen" && [
      themed($contentFullscreen),
      { paddingTop: insets.top, paddingBottom: insets.bottom },
    ],
    $contentStyleOverride,
  ]

  const $titleStyle: StyleProp<TextStyle> = [
    themed($titleBase),
    preset === "bottom" && $titleBottom,
    $titleStyleOverride,
  ]

  const renderHeader = () =>
    hasTitleArea ? (
      <View style={preset === "bottom" ? $headerBottom : $header}>
        {(titleTx || title) && (
          <Text
            preset="subheading"
            tx={titleTx}
            text={title}
            txOptions={titleTxOptions}
            style={$titleStyle}
          />
        )}
        {showCloseButton && (
          <Pressable
            onPress={onClose}
            style={[themed($closeButton), preset === "bottom" && $closeButtonBottom]}
            hitSlop={{ top: s(10), bottom: s(10), left: s(10), right: s(10) }}
            accessibilityRole="button"
            accessibilityLabel="Close"
          >
            <Icon icon="x" size={20} color={theme.colors.textDim} />
          </Pressable>
        )}
      </View>
    ) : null

  const renderFooter = () =>
    hasFooter ? (
      <View style={themed($footer)}>
        {FooterComponent ? (
          FooterComponent
        ) : (
          <>
            {cancelButtonProps && (
              <Button preset="default" style={themed($footerButton)} {...cancelButtonProps} />
            )}
            {confirmButtonProps && (
              <Button preset="filled" style={themed($footerButton)} {...confirmButtonProps} />
            )}
          </>
        )}
      </View>
    ) : null

  // For bottom preset, wrap content in KeyboardAwareScrollView
  const renderContent = () => {
    if (preset === "bottom") {
      return (
        <KeyboardAwareScrollView
          bottomOffset={Platform.OS === "ios" ? 20 : 0}
          keyboardShouldPersistTaps="handled"
          showsVerticalScrollIndicator={false}
          contentContainerStyle={$scrollContent}
        >
          {renderHeader()}
          <View style={themed($body)}>{children}</View>
          {renderFooter()}
        </KeyboardAwareScrollView>
      )
    }

    return (
      <>
        {renderHeader()}
        <View style={themed($body)}>{children}</View>
        {renderFooter()}
      </>
    )
  }

  return (
    <RNModal
      visible={visible}
      transparent
      animationType={resolvedAnimationType}
      onRequestClose={onClose}
      statusBarTranslucent
      {...rest}
    >
      <Pressable style={$overlayStyle} onPress={closeOnOverlayPress ? onClose : undefined}>
        <Pressable style={$contentContainerStyle} onPress={(e) => e.stopPropagation()}>
          {/* Drag Handle for bottom preset */}
          {preset === "bottom" && <View style={themed($dragHandle)} />}

          {renderContent()}
        </Pressable>
      </Pressable>
    </RNModal>
  )
}

// Base styles
const $overlayBase: ThemedStyle<ViewStyle> = () => ({
  flex: 1,
  backgroundColor: "rgba(0, 0, 0, 0.5)",
})

const $contentBase: ThemedStyle<ViewStyle> = ({ colors, spacing }) => ({
  backgroundColor: colors.background,
  paddingHorizontal: spacing.lg,
  paddingVertical: spacing.md,
})

// Center preset styles
const $overlayCenter: ThemedStyle<ViewStyle> = () => ({
  justifyContent: "center",
  alignItems: "center",
  padding: s(24),
})

const $contentCenter: ThemedStyle<ViewStyle> = () => ({
  borderRadius: s(12),
  width: "100%",
  overflow: "hidden",
})

// Bottom preset styles
const $overlayBottom: ViewStyle = {
  justifyContent: "flex-end",
}

const $contentBottom: ThemedStyle<ViewStyle> = ({ spacing }) => ({
  borderTopLeftRadius: s(20),
  borderTopRightRadius: s(20),
  paddingTop: spacing.sm,
  maxHeight: "90%",
})

const $dragHandle: ThemedStyle<ViewStyle> = ({ colors, spacing }) => ({
  width: s(36),
  height: s(4),
  borderRadius: s(2),
  backgroundColor: colors.separator,
  alignSelf: "center",
  marginBottom: spacing.sm,
})

const $titleBottom: TextStyle = {
  textAlign: "center",
}

// Fullscreen preset styles
const $overlayFullscreen: ViewStyle = {
  backgroundColor: "transparent",
}

const $contentFullscreen: ThemedStyle<ViewStyle> = () => ({
  flex: 1,
  borderRadius: 0,
})

// Common styles
const $header: ViewStyle = {
  flexDirection: "row",
  alignItems: "center",
  justifyContent: "space-between",
}

const $headerBottom: ViewStyle = {
  alignItems: "center",
  justifyContent: "center",
}

const $titleBase: ThemedStyle<TextStyle> = () => ({
  textAlign: "left",
})

const $closeButton: ThemedStyle<ViewStyle> = ({ spacing }) => ({
  padding: spacing.xxs,
  marginLeft: spacing.sm,
})

const $closeButtonBottom: ViewStyle = {
  position: "absolute",
  right: 0,
  top: 0,
}

const $body: ThemedStyle<ViewStyle> = ({ spacing }) => ({
  paddingVertical: spacing.md,
})

const $footer: ThemedStyle<ViewStyle> = ({ spacing }) => ({
  flexDirection: "row",
  justifyContent: "flex-end",
  gap: spacing.sm,
  paddingTop: spacing.sm,
})

const $footerButton: ThemedStyle<ViewStyle> = () => ({
  minWidth: s(80),
})

const $scrollContent: ViewStyle = {
  flexGrow: 1,
}
