import React from 'react'
import { render, fireEvent } from '@testing-library/react-native'
import Text from './Text'

describe('Text Component', () => {
  describe('Basic Rendering', () => {
    it('should render basic text with default dark theme color', () => {
      const { getByText } = render(<Text>Hello World</Text>)

      const textElement = getByText('Hello World')
      expect(textElement).toBeTruthy()
      expect(textElement.props.style).toEqual(
        expect.objectContaining({
          color: '#F5F5F5',
        })
      )
    })

    it('should render children correctly', () => {
      const { getByText } = render(<Text>Test Content</Text>)

      expect(getByText('Test Content')).toBeTruthy()
    })

    it('should render nested text elements', () => {
      const { getByText } = render(
        <Text>
          Parent <Text>Child</Text>
        </Text>
      )

      // In React Native, nested Text components are flattened into a single text node
      expect(getByText('Parent Child')).toBeTruthy()
      expect(getByText('Child')).toBeTruthy()
    })

    it('should have correct displayName', () => {
      expect(Text.displayName).toBe('Text')
    })
  })

  describe('Style Merging', () => {
    it('should merge custom object style with default style', () => {
      const customStyle = { fontSize: 16, fontWeight: '600' as const }
      const { getByText } = render(<Text style={customStyle}>Styled Text</Text>)

      const textElement = getByText('Styled Text')
      expect(textElement.props.style).toEqual(
        expect.objectContaining({
          color: '#F5F5F5',
          fontSize: 16,
          fontWeight: '600',
        })
      )
    })

    it('should merge custom array style with default style', () => {
      const styleArray = [{ fontSize: 14 }, { fontWeight: '500' as const }]
      const { getByText } = render(<Text style={styleArray}>Array Style</Text>)

      const textElement = getByText('Array Style')
      // Array style should be merged as [defaultStyle, ...styleArray]
      expect(textElement.props.style).toContainEqual({ color: '#F5F5F5' })
      expect(textElement.props.style).toContainEqual({ fontSize: 14 })
      expect(textElement.props.style).toContainEqual({ fontWeight: '500' })
    })

    it('should allow overriding default color', () => {
      const { getByText } = render(
        <Text style={{ color: '#FF0000' }}>Red Text</Text>
      )

      const textElement = getByText('Red Text')
      expect(textElement.props.style.color).toBe('#FF0000')
    })

    it('should pass className through correctly', () => {
      const { getByText } = render(<Text className="text-primary">Class Text</Text>)

      const textElement = getByText('Class Text')
      expect(textElement.props.className).toBe('text-primary')
    })
  })

  describe('onClick Handler', () => {
    it('should create TouchableOpacity wrapper when onClick is provided', () => {
      const mockOnClick = jest.fn()
      const { getByText } = render(<Text onClick={mockOnClick}>Clickable Text</Text>)

      const textElement = getByText('Clickable Text')
      // Parent should be TouchableOpacity (or TouchableWithoutFeedback depending on implementation)
      expect(textElement.parent).toBeTruthy()
    })

    it('should call onClick handler when pressed', () => {
      const mockOnClick = jest.fn()
      const { getByText } = render(<Text onClick={mockOnClick}>Click Me</Text>)

      const textElement = getByText('Click Me')
      fireEvent.press(textElement)

      expect(mockOnClick).toHaveBeenCalledTimes(1)
    })

    it('should pass touchProps to TouchableOpacity', () => {
      const mockOnClick = jest.fn()
      const touchProps = {
        testID: 'touchable-test',
        activeOpacity: 0.5,
      }

      const { getByTestId } = render(
        <Text onClick={mockOnClick} touchProps={touchProps}>
          Touchable Text
        </Text>
      )

      expect(getByTestId('touchable-test')).toBeTruthy()
    })

    it('should not interfere with normal text rendering when onClick is not provided', () => {
      const { getByText } = render(<Text>Normal Text</Text>)

      const textElement = getByText('Normal Text')
      expect(textElement).toBeTruthy()
      // Should be plain Text element, not wrapped
      expect(textElement.parent.type).not.toBe('TouchableOpacity')
    })
  })

  describe('Animated Text', () => {
    it('should render Animated.Text when animated prop is true', () => {
      const { getByText } = render(<Text animated={true}>Animated Text</Text>)

      const textElement = getByText('Animated Text')
      expect(textElement).toBeTruthy()
      // Animated.Text should still render the content
    })

    it('should pass style to Animated.Text component', () => {
      const customStyle = { fontSize: 20 }
      const { getByText } = render(
        <Text animated={true} style={customStyle}>
          Animated Styled
        </Text>
      )

      const textElement = getByText('Animated Styled')
      expect(textElement.props.style).toEqual(
        expect.objectContaining({
          color: '#F5F5F5',
          fontSize: 20,
        })
      )
    })
  })

  describe('Props Forwarding', () => {
    it('should forward standard RN Text props', () => {
      const { getByText } = render(
        <Text numberOfLines={2} ellipsizeMode="tail">
          Long text that should be truncated
        </Text>
      )

      const textElement = getByText(/Long text/)
      expect(textElement.props.numberOfLines).toBe(2)
      expect(textElement.props.ellipsizeMode).toBe('tail')
    })

    it('should forward accessibility props', () => {
      const { getByText } = render(
        <Text accessibilityLabel="Label text" accessible={true}>
          Content
        </Text>
      )

      const textElement = getByText('Content')
      expect(textElement.props.accessibilityLabel).toBe('Label text')
      expect(textElement.props.accessible).toBe(true)
    })

    it('should forward testID prop', () => {
      const { getByTestId } = render(<Text testID="text-test-id">Test Content</Text>)

      expect(getByTestId('text-test-id')).toBeTruthy()
    })

    it('should forward onPress through onClick', () => {
      const mockOnPress = jest.fn()
      const { getByText } = render(<Text onClick={mockOnPress}>Press Me</Text>)

      const textElement = getByText('Press Me')
      fireEvent.press(textElement)

      expect(mockOnPress).toHaveBeenCalled()
    })
  })

  describe('Edge Cases', () => {
    it('should handle empty string children', () => {
      const { getByText } = render(<Text></Text>)

      // Empty text should still render
      const textElement = getByText('')
      expect(textElement).toBeTruthy()
    })

    it('should handle null children gracefully', () => {
      // null should not cause crash, component renders but with no text content
      const result = render(<Text>{null}</Text>)
      expect(result).toBeTruthy()
    })

    it('should handle style as undefined', () => {
      const { getByText } = render(<Text style={undefined}>No Style</Text>)

      const textElement = getByText('No Style')
      expect(textElement.props.style).toEqual({ color: '#F5F5F5' })
    })

    it('should handle className as undefined', () => {
      const { getByText } = render(<Text className={undefined}>No Class</Text>)

      const textElement = getByText('No Class')
      expect(textElement.props.className).toBe('')
    })

    it('should handle complex style objects', () => {
      const complexStyle = {
        fontSize: 16,
        fontWeight: 'bold' as const,
        lineHeight: 24,
        letterSpacing: 0.5,
        textTransform: 'uppercase' as const,
      }

      const { getByText } = render(<Text style={complexStyle}>Complex Style</Text>)

      const textElement = getByText('Complex Style')
      expect(textElement.props.style).toEqual(
        expect.objectContaining({
          color: '#F5F5F5',
          fontSize: 16,
          fontWeight: 'bold',
          lineHeight: 24,
          letterSpacing: 0.5,
          textTransform: 'uppercase',
        })
      )
    })

    it('should prioritize onClick over animated when both are provided', () => {
      const mockOnClick = jest.fn()
      const { getByText } = render(
        <Text onClick={mockOnClick} animated={true}>
          Both Props
        </Text>
      )

      const textElement = getByText('Both Props')
      // animated prop takes precedence in the conditional rendering
      // onClick is ignored when animated is true based on the implementation
    })
  })

  describe('Integration with Other Components', () => {
    it('should work within a View component', () => {
      const { getByText } = render(
        <Text>
          <Text>Nested</Text> Text
        </Text>
      )

      // In React Native, nested Text components are flattened into a single text node
      expect(getByText('Nested Text')).toBeTruthy()
      expect(getByText('Nested')).toBeTruthy()
    })

    it('should handle multiple onClick handlers correctly', () => {
      const onClick1 = jest.fn()
      const onClick2 = jest.fn()

      const { getByText } = render(
        <>
          <Text onClick={onClick1}>First</Text>
          <Text onClick={onClick2}>Second</Text>
        </>
      )

      fireEvent.press(getByText('First'))
      fireEvent.press(getByText('Second'))

      expect(onClick1).toHaveBeenCalledTimes(1)
      expect(onClick2).toHaveBeenCalledTimes(1)
    })
  })
})
