import type { TopBarProps } from '../index'
import { render, screen } from '@testing-library/react'
import { TopBar } from '../index'

// Mock next/link to capture href values
vi.mock('@/next/link', () => ({
  default: ({ children, href, replace, className }: { children: React.ReactNode, href: string, replace?: boolean, className?: string }) => (
    <a href={href} data-replace={replace} className={className} data-testid="back-link">
      {children}
    </a>
  ),
}))

// Helper to render TopBar with default props
const renderTopBar = (props: Partial<TopBarProps> = {}) => {
  const defaultProps: TopBarProps = {
    activeIndex: 0,
    ...props,
  }
  return {
    ...render(<TopBar {...defaultProps} />),
    props: defaultProps,
  }
}

// TopBar Component Tests
describe('TopBar', () => {
  beforeEach(() => {
    vi.clearAllMocks()
  })

  // Rendering Tests - Verify component renders properly
  describe('Rendering', () => {
    it('should render without crashing', () => {
      renderTopBar()

      expect(screen.getByTestId('back-link')).toBeInTheDocument()
    })

    it('should render back link with arrow icon', () => {
      const { container } = renderTopBar()

      const backLink = screen.getByTestId('back-link')
      expect(backLink).toBeInTheDocument()
      // Check for the arrow icon (svg element)
      const arrowIcon = container.querySelector('svg')
      expect(arrowIcon).toBeInTheDocument()
    })

    it('should render fallback route text', () => {
      renderTopBar()

      expect(screen.getByText('datasetCreation.steps.header.fallbackRoute')).toBeInTheDocument()
    })

    it('should render Stepper component with 3 steps', () => {
      renderTopBar({ activeIndex: 0 })

      // Assert - Check for step translations
      expect(screen.getByText('datasetCreation.steps.one')).toBeInTheDocument()
      expect(screen.getByText('datasetCreation.steps.two')).toBeInTheDocument()
      expect(screen.getByText('datasetCreation.steps.three')).toBeInTheDocument()
    })

    it('should apply default container classes', () => {
      const { container } = renderTopBar()

      const wrapper = container.firstChild as HTMLElement
      expect(wrapper).toHaveClass('relative')
      expect(wrapper).toHaveClass('flex')
      expect(wrapper).toHaveClass('h-[52px]')
      expect(wrapper).toHaveClass('shrink-0')
      expect(wrapper).toHaveClass('items-center')
      expect(wrapper).toHaveClass('justify-between')
      expect(wrapper).toHaveClass('border-b')
      expect(wrapper).toHaveClass('border-b-divider-subtle')
    })
  })

  // Props Testing - Test all prop variations
  describe('Props', () => {
    describe('className prop', () => {
      it('should apply custom className when provided', () => {
        const { container } = renderTopBar({ className: 'custom-class' })

        const wrapper = container.firstChild as HTMLElement
        expect(wrapper).toHaveClass('custom-class')
      })

      it('should merge custom className with default classes', () => {
        const { container } = renderTopBar({ className: 'my-custom-class another-class' })

        const wrapper = container.firstChild as HTMLElement
        expect(wrapper).toHaveClass('relative')
        expect(wrapper).toHaveClass('flex')
        expect(wrapper).toHaveClass('my-custom-class')
        expect(wrapper).toHaveClass('another-class')
      })

      it('should render correctly without className', () => {
        const { container } = renderTopBar({ className: undefined })

        const wrapper = container.firstChild as HTMLElement
        expect(wrapper).toHaveClass('relative')
        expect(wrapper).toHaveClass('flex')
      })

      it('should handle empty string className', () => {
        const { container } = renderTopBar({ className: '' })

        const wrapper = container.firstChild as HTMLElement
        expect(wrapper).toHaveClass('relative')
      })
    })

    describe('datasetId prop', () => {
      it('should set fallback route to /datasets when datasetId is undefined', () => {
        renderTopBar({ datasetId: undefined })

        const backLink = screen.getByTestId('back-link')
        expect(backLink).toHaveAttribute('href', '/datasets')
      })

      it('should set fallback route to /datasets/:id/documents when datasetId is provided', () => {
        renderTopBar({ datasetId: 'dataset-123' })

        const backLink = screen.getByTestId('back-link')
        expect(backLink).toHaveAttribute('href', '/datasets/dataset-123/documents')
      })

      it('should handle various datasetId formats', () => {
        renderTopBar({ datasetId: 'abc-def-ghi-123' })

        const backLink = screen.getByTestId('back-link')
        expect(backLink).toHaveAttribute('href', '/datasets/abc-def-ghi-123/documents')
      })

      it('should handle empty string datasetId', () => {
        renderTopBar({ datasetId: '' })

        // Assert - Empty string is falsy, so fallback to /datasets
        const backLink = screen.getByTestId('back-link')
        expect(backLink).toHaveAttribute('href', '/datasets')
      })
    })

    describe('activeIndex prop', () => {
      it('should pass activeIndex to Stepper component (index 0)', () => {
        const { container } = renderTopBar({ activeIndex: 0 })

        // Assert - First step should be active (has specific styling)
        const steps = container.querySelectorAll('[class*="system-2xs-semibold-uppercase"]')
        expect(steps.length).toBeGreaterThan(0)
      })

      it('should pass activeIndex to Stepper component (index 1)', () => {
        renderTopBar({ activeIndex: 1 })

        // Assert - Stepper is rendered with correct props
        expect(screen.getByText('datasetCreation.steps.one')).toBeInTheDocument()
        expect(screen.getByText('datasetCreation.steps.two')).toBeInTheDocument()
      })

      it('should pass activeIndex to Stepper component (index 2)', () => {
        renderTopBar({ activeIndex: 2 })

        expect(screen.getByText('datasetCreation.steps.three')).toBeInTheDocument()
      })

      it('should handle edge case activeIndex of -1', () => {
        const { container } = renderTopBar({ activeIndex: -1 })

        // Assert - Component should render without crashing
        expect(container.firstChild).toBeInTheDocument()
      })

      it('should handle edge case activeIndex beyond steps length', () => {
        const { container } = renderTopBar({ activeIndex: 10 })

        // Assert - Component should render without crashing
        expect(container.firstChild).toBeInTheDocument()
      })
    })
  })

  // Memoization Tests - Test useMemo logic and dependencies
  describe('Memoization Logic', () => {
    it('should compute fallbackRoute based on datasetId', () => {
      // Arrange & Act - With datasetId
      const { rerender } = render(<TopBar activeIndex={0} datasetId="test-id" />)

      expect(screen.getByTestId('back-link')).toHaveAttribute('href', '/datasets/test-id/documents')

      // Act - Rerender with different datasetId
      rerender(<TopBar activeIndex={0} datasetId="new-id" />)

      // Assert - Route should update
      expect(screen.getByTestId('back-link')).toHaveAttribute('href', '/datasets/new-id/documents')
    })

    it('should update fallbackRoute when datasetId changes from undefined to defined', () => {
      const { rerender } = render(<TopBar activeIndex={0} />)
      expect(screen.getByTestId('back-link')).toHaveAttribute('href', '/datasets')

      rerender(<TopBar activeIndex={0} datasetId="new-dataset" />)

      expect(screen.getByTestId('back-link')).toHaveAttribute('href', '/datasets/new-dataset/documents')
    })

    it('should update fallbackRoute when datasetId changes from defined to undefined', () => {
      const { rerender } = render(<TopBar activeIndex={0} datasetId="existing-id" />)
      expect(screen.getByTestId('back-link')).toHaveAttribute('href', '/datasets/existing-id/documents')

      rerender(<TopBar activeIndex={0} datasetId={undefined} />)

      expect(screen.getByTestId('back-link')).toHaveAttribute('href', '/datasets')
    })

    it('should not change fallbackRoute when activeIndex changes but datasetId stays same', () => {
      const { rerender } = render(<TopBar activeIndex={0} datasetId="stable-id" />)
      const initialHref = screen.getByTestId('back-link').getAttribute('href')

      rerender(<TopBar activeIndex={1} datasetId="stable-id" />)

      // Assert - href should remain the same
      expect(screen.getByTestId('back-link')).toHaveAttribute('href', initialHref)
    })

    it('should not change fallbackRoute when className changes but datasetId stays same', () => {
      const { rerender } = render(<TopBar activeIndex={0} datasetId="stable-id" className="class-1" />)
      const initialHref = screen.getByTestId('back-link').getAttribute('href')

      rerender(<TopBar activeIndex={0} datasetId="stable-id" className="class-2" />)

      // Assert - href should remain the same
      expect(screen.getByTestId('back-link')).toHaveAttribute('href', initialHref)
    })
  })

  // Link Component Tests
  describe('Link Component', () => {
    it('should render Link with replace prop', () => {
      renderTopBar()

      const backLink = screen.getByTestId('back-link')
      expect(backLink).toHaveAttribute('data-replace', 'true')
    })

    it('should render Link with correct classes', () => {
      renderTopBar()

      const backLink = screen.getByTestId('back-link')
      expect(backLink).toHaveClass('inline-flex')
      expect(backLink).toHaveClass('h-12')
      expect(backLink).toHaveClass('items-center')
      expect(backLink).toHaveClass('justify-start')
      expect(backLink).toHaveClass('gap-1')
      expect(backLink).toHaveClass('py-2')
      expect(backLink).toHaveClass('pl-2')
      expect(backLink).toHaveClass('pr-6')
    })
  })

  // STEP_T_MAP Tests - Verify step translations
  describe('STEP_T_MAP Translations', () => {
    it('should render step one translation', () => {
      renderTopBar({ activeIndex: 0 })

      expect(screen.getByText('datasetCreation.steps.one')).toBeInTheDocument()
    })

    it('should render step two translation', () => {
      renderTopBar({ activeIndex: 1 })

      expect(screen.getByText('datasetCreation.steps.two')).toBeInTheDocument()
    })

    it('should render step three translation', () => {
      renderTopBar({ activeIndex: 2 })

      expect(screen.getByText('datasetCreation.steps.three')).toBeInTheDocument()
    })

    it('should render all three step translations', () => {
      renderTopBar({ activeIndex: 0 })

      expect(screen.getByText('datasetCreation.steps.one')).toBeInTheDocument()
      expect(screen.getByText('datasetCreation.steps.two')).toBeInTheDocument()
      expect(screen.getByText('datasetCreation.steps.three')).toBeInTheDocument()
    })
  })

  // Edge Cases and Error Handling Tests
  describe('Edge Cases', () => {
    it('should handle special characters in datasetId', () => {
      renderTopBar({ datasetId: 'dataset-with-special_chars.123' })

      const backLink = screen.getByTestId('back-link')
      expect(backLink).toHaveAttribute('href', '/datasets/dataset-with-special_chars.123/documents')
    })

    it('should handle very long datasetId', () => {
      const longId = 'a'.repeat(100)

      renderTopBar({ datasetId: longId })

      const backLink = screen.getByTestId('back-link')
      expect(backLink).toHaveAttribute('href', `/datasets/${longId}/documents`)
    })

    it('should handle UUID format datasetId', () => {
      const uuid = '550e8400-e29b-41d4-a716-446655440000'

      renderTopBar({ datasetId: uuid })

      const backLink = screen.getByTestId('back-link')
      expect(backLink).toHaveAttribute('href', `/datasets/${uuid}/documents`)
    })

    it('should handle whitespace in className', () => {
      const { container } = renderTopBar({ className: '  spaced-class  ' })

      // Assert - classNames utility handles whitespace
      const wrapper = container.firstChild as HTMLElement
      expect(wrapper).toBeInTheDocument()
    })

    it('should render correctly with all props provided', () => {
      const { container } = renderTopBar({
        className: 'custom-class',
        datasetId: 'full-props-id',
        activeIndex: 2,
      })

      const wrapper = container.firstChild as HTMLElement
      expect(wrapper).toHaveClass('custom-class')
      expect(screen.getByTestId('back-link')).toHaveAttribute('href', '/datasets/full-props-id/documents')
    })

    it('should render correctly with minimal props (only activeIndex)', () => {
      const { container } = renderTopBar({ activeIndex: 0 })

      expect(container.firstChild).toBeInTheDocument()
      expect(screen.getByTestId('back-link')).toHaveAttribute('href', '/datasets')
    })
  })

  // Stepper Integration Tests
  describe('Stepper Integration', () => {
    it('should pass steps array with correct structure to Stepper', () => {
      renderTopBar({ activeIndex: 0 })

      // Assert - All step names should be rendered
      const stepOne = screen.getByText('datasetCreation.steps.one')
      const stepTwo = screen.getByText('datasetCreation.steps.two')
      const stepThree = screen.getByText('datasetCreation.steps.three')

      expect(stepOne).toBeInTheDocument()
      expect(stepTwo).toBeInTheDocument()
      expect(stepThree).toBeInTheDocument()
    })

    it('should render Stepper in centered position', () => {
      const { container } = renderTopBar({ activeIndex: 0 })

      // Assert - Check for centered positioning classes
      const centeredContainer = container.querySelector('.absolute.left-1\\/2.top-1\\/2.-translate-x-1\\/2.-translate-y-1\\/2')
      expect(centeredContainer).toBeInTheDocument()
    })

    it('should render step dividers between steps', () => {
      const { container } = renderTopBar({ activeIndex: 0 })

      // Assert - Check for dividers (h-px w-4 bg-divider-deep)
      const dividers = container.querySelectorAll('.h-px.w-4.bg-divider-deep')
      expect(dividers.length).toBe(2) // 2 dividers between 3 steps
    })
  })

  describe('Accessibility', () => {
    it('should have accessible back link', () => {
      renderTopBar()

      const backLink = screen.getByTestId('back-link')
      expect(backLink).toBeInTheDocument()
      // Link should have visible text
      expect(screen.getByText('datasetCreation.steps.header.fallbackRoute')).toBeInTheDocument()
    })

    it('should have visible arrow icon in back link', () => {
      const { container } = renderTopBar()

      // Assert - Arrow icon should be visible
      const arrowIcon = container.querySelector('svg')
      expect(arrowIcon).toBeInTheDocument()
      expect(arrowIcon).toHaveClass('text-text-primary')
    })
  })

  // Re-render Tests
  describe('Re-render Behavior', () => {
    it('should update activeIndex on re-render', () => {
      const { rerender, container } = render(<TopBar activeIndex={0} />)

      // Initial check
      expect(container.firstChild).toBeInTheDocument()

      // Act - Update activeIndex
      rerender(<TopBar activeIndex={1} />)

      // Assert - Component should still render
      expect(container.firstChild).toBeInTheDocument()
    })

    it('should update className on re-render', () => {
      const { rerender, container } = render(<TopBar activeIndex={0} className="initial-class" />)
      const wrapper = container.firstChild as HTMLElement
      expect(wrapper).toHaveClass('initial-class')

      rerender(<TopBar activeIndex={0} className="updated-class" />)

      expect(wrapper).toHaveClass('updated-class')
      expect(wrapper).not.toHaveClass('initial-class')
    })

    it('should handle multiple rapid re-renders', () => {
      const { rerender, container } = render(<TopBar activeIndex={0} />)

      // Act - Multiple rapid re-renders
      rerender(<TopBar activeIndex={1} />)
      rerender(<TopBar activeIndex={2} />)
      rerender(<TopBar activeIndex={0} datasetId="new-id" />)
      rerender(<TopBar activeIndex={1} datasetId="another-id" className="new-class" />)

      // Assert - Component should be stable
      expect(container.firstChild).toBeInTheDocument()
      const wrapper = container.firstChild as HTMLElement
      expect(wrapper).toHaveClass('new-class')
      expect(screen.getByTestId('back-link')).toHaveAttribute('href', '/datasets/another-id/documents')
    })
  })
})
