import {
  createContext,
  FC,
  PropsWithChildren,
  useCallback,
  useContext,
  useEffect,
  useMemo,
  useRef,
  useState,
} from "react"
// eslint-disable-next-line no-restricted-imports
import { Animated, Modal, TextStyle, View, ViewStyle } from "react-native"
import { useSafeAreaInsets } from "react-native-safe-area-context"

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

export type ToastType = "success" | "error" | "warning" | "info"

export interface ToastConfig {
  message: string
  type?: ToastType
  duration?: number
}

export interface ToastContextType {
  show: (config: ToastConfig) => void
  success: (message: string, duration?: number) => void
  error: (message: string, duration?: number) => void
  warning: (message: string, duration?: number) => void
  info: (message: string, duration?: number) => void
  hide: () => void
}

// Default durations by type (in ms)
const DEFAULT_DURATIONS: Record<ToastType, number> = {
  success: 3000,
  error: 5000, // Errors show longer
  warning: 4000,
  info: 3000,
}

const ToastContext = createContext<ToastContextType | null>(null)

export const ToastProvider: FC<PropsWithChildren> = ({ children }) => {
  const [visible, setVisible] = useState(false)
  const [config, setConfig] = useState<ToastConfig>({ message: "" })
  const timeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null)
  const fadeAnim = useRef(new Animated.Value(0)).current
  const insets = useSafeAreaInsets()

  const {
    themed,
    theme: { colors },
  } = useAppTheme()

  // Clear timeout on unmount
  useEffect(() => {
    return () => {
      if (timeoutRef.current) {
        clearTimeout(timeoutRef.current)
      }
    }
  }, [])

  const hide = useCallback(() => {
    // Clear any pending timeout
    if (timeoutRef.current) {
      clearTimeout(timeoutRef.current)
      timeoutRef.current = null
    }
    // Fade out animation
    Animated.timing(fadeAnim, {
      toValue: 0,
      duration: 200,
      useNativeDriver: true,
    }).start(() => {
      setVisible(false)
    })
  }, [fadeAnim])

  const show = useCallback(
    (newConfig: ToastConfig) => {
      // Clear any existing timeout to prevent premature hide
      if (timeoutRef.current) {
        clearTimeout(timeoutRef.current)
        timeoutRef.current = null
      }

      setConfig(newConfig)
      setVisible(true)

      // Fade in animation
      fadeAnim.setValue(0)
      Animated.timing(fadeAnim, {
        toValue: 1,
        duration: 200,
        useNativeDriver: true,
      }).start()

      // Auto hide after duration (use type-specific default if not provided)
      const type = newConfig.type ?? "info"
      const duration = newConfig.duration ?? DEFAULT_DURATIONS[type]
      timeoutRef.current = setTimeout(() => {
        hide()
      }, duration)
    },
    [hide, fadeAnim],
  )

  const success = useCallback(
    (message: string, duration?: number) => {
      show({ message, type: "success", duration })
    },
    [show],
  )

  const error = useCallback(
    (message: string, duration?: number) => {
      show({ message, type: "error", duration })
    },
    [show],
  )

  const warning = useCallback(
    (message: string, duration?: number) => {
      show({ message, type: "warning", duration })
    },
    [show],
  )

  const info = useCallback(
    (message: string, duration?: number) => {
      show({ message, type: "info", duration })
    },
    [show],
  )

  const value = useMemo(
    () => ({ show, success, error, warning, info, hide }),
    [show, success, error, warning, info, hide],
  )

  const getBackgroundColor = (type: ToastType = "info") => {
    switch (type) {
      case "success":
        return colors.palette.primary500
      case "error":
        return colors.error
      case "warning":
        return colors.palette.accent500
      case "info":
      default:
        return colors.palette.secondary400
    }
  }

  const getTextColor = (type: ToastType = "info") => {
    switch (type) {
      case "warning":
        return colors.palette.neutral800
      default:
        return colors.palette.neutral100
    }
  }

  return (
    <ToastContext.Provider value={value}>
      {children}
      <Modal
        visible={visible}
        transparent
        animationType="fade"
        presentationStyle="overFullScreen"
        statusBarTranslucent
        onRequestClose={hide}
      >
        <Animated.View
          pointerEvents="none"
          style={[$overlay, { paddingTop: insets.top + 20 }, { opacity: fadeAnim }]}
        >
          <View
            style={[themed($toastContainer), { backgroundColor: getBackgroundColor(config.type) }]}
          >
            <Text
              text={config.message}
              size="sm"
              style={[themed($toastText), { color: getTextColor(config.type) }]}
            />
          </View>
        </Animated.View>
      </Modal>
    </ToastContext.Provider>
  )
}

export const useToast = (): ToastContextType => {
  const context = useContext(ToastContext)
  if (!context) {
    throw new Error("useToast must be used within a ToastProvider")
  }
  return context
}

const $overlay: ViewStyle = {
  flex: 1,
  alignItems: "center",
}

const $toastContainer: ThemedStyle<ViewStyle> = ({ spacing }) => ({
  minWidth: s(120),
  maxWidth: "80%",
  paddingVertical: spacing.md,
  paddingHorizontal: spacing.lg,
  borderRadius: s(8),
  shadowColor: "#000",
  shadowOffset: { width: 0, height: s(2) },
  shadowOpacity: 0.25,
  shadowRadius: s(4),
  elevation: 5,
})

const $toastText: ThemedStyle<TextStyle> = () => ({
  textAlign: "center",
})
