import { ComponentType } from "react"
import {
  StyleProp,
  TouchableOpacity,
  TouchableOpacityProps,
  View,
  ViewProps,
  ViewStyle,
} from "react-native"
import {
  ArrowLeft,
  BarChart2,
  Bell,
  Bug,
  Camera,
  Check,
  ChevronLeft,
  ChevronRight,
  Copy,
  CreditCard,
  Eye,
  EyeOff,
  FileText,
  Github,
  Globe,
  HandMetal,
  Heart,
  Home,
  Info,
  Layers,
  Lock,
  LogOut,
  Mail,
  MapPin,
  Menu,
  MessageSquare,
  Mic,
  Monitor,
  Moon,
  MoreHorizontal,
  Pencil,
  Settings,
  Shield,
  Smartphone,
  Sun,
  Tablet,
  Tag,
  User,
  Users,
  X,
  LucideProps,
} from "lucide-react-native"

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

// Map icon names to Lucide components
const iconRegistry: Record<string, ComponentType<LucideProps>> = {
  back: ArrowLeft,
  barChart: BarChart2,
  bell: Bell,
  camera: Camera,
  caretLeft: ChevronLeft,
  caretRight: ChevronRight,
  check: Check,
  clap: HandMetal,
  community: Users,
  components: Layers,
  copy: Copy,
  creditCard: CreditCard,
  debug: Bug,
  fileText: FileText,
  github: Github,
  globe: Globe,
  heart: Heart,
  hidden: EyeOff,
  home: Home,
  info: Info,
  ladybug: Bug,
  lock: Lock,
  logout: LogOut,
  mail: Mail,
  menu: Menu,
  monitor: Monitor,
  moon: Moon,
  more: MoreHorizontal,
  pencil: Pencil,
  pin: MapPin,
  podcast: Mic,
  settings: Settings,
  shield: Shield,
  slack: MessageSquare,
  smartphone: Smartphone,
  sun: Sun,
  tablet: Tablet,
  tag: Tag,
  user: User,
  view: Eye,
  x: X,
}

export type IconTypes = keyof typeof iconRegistry

type BaseIconProps = {
  /**
   * The name of the icon
   */
  icon: IconTypes

  /**
   * An optional tint color for the icon
   */
  color?: string

  /**
   * An optional size for the icon. If not provided, defaults to 24.
   */
  size?: number

  /**
   * Style overrides for the icon container
   */
  containerStyle?: StyleProp<ViewStyle>

  /**
   * Stroke width for the icon (default: 2)
   */
  strokeWidth?: number
}

type PressableIconProps = Omit<TouchableOpacityProps, "style"> & BaseIconProps
type IconProps = Omit<ViewProps, "style"> & BaseIconProps

/**
 * A component to render a registered icon.
 * It is wrapped in a <TouchableOpacity />
 * @see [Documentation and Examples]{@link https://docs.infinite.red/ignite-cli/boilerplate/app/components/Icon/}
 * @param {PressableIconProps} props - The props for the `PressableIcon` component.
 * @returns {JSX.Element} The rendered `PressableIcon` component.
 */
export function PressableIcon(props: PressableIconProps) {
  const {
    icon,
    color,
    size = s(24),
    containerStyle: $containerStyleOverride,
    strokeWidth = 2,
    ...pressableProps
  } = props

  const { theme } = useAppTheme()
  const IconComponent = iconRegistry[icon]

  if (!IconComponent) {
    if (__DEV__) console.warn(`Icon "${icon}" not found in registry`)
    return null
  }

  return (
    <TouchableOpacity {...pressableProps} style={$containerStyleOverride}>
      <IconComponent color={color ?? theme.colors.text} size={size} strokeWidth={strokeWidth} />
    </TouchableOpacity>
  )
}

/**
 * A component to render a registered icon.
 * It is wrapped in a <View />, use `PressableIcon` if you want to react to input
 * @see [Documentation and Examples]{@link https://docs.infinite.red/ignite-cli/boilerplate/app/components/Icon/}
 * @param {IconProps} props - The props for the `Icon` component.
 * @returns {JSX.Element} The rendered `Icon` component.
 */
export function Icon(props: IconProps) {
  const {
    icon,
    color,
    size = s(24),
    containerStyle: $containerStyleOverride,
    strokeWidth = 2,
    ...viewProps
  } = props

  const { theme } = useAppTheme()
  const IconComponent = iconRegistry[icon]

  if (!IconComponent) {
    if (__DEV__) console.warn(`Icon "${icon}" not found in registry`)
    return null
  }

  return (
    <View {...viewProps} style={$containerStyleOverride}>
      <IconComponent color={color ?? theme.colors.text} size={size} strokeWidth={strokeWidth} />
    </View>
  )
}

export { iconRegistry }
