import {describe, expect, it, vi, beforeEach} from 'vitest'

import {render, screen, userEvent} from '../../test-utils'

import {TransitionLink} from './transition-link'

// Mock react-router hooks
const mockNavigate = vi.fn()
vi.mock('react-router', () => ({
  useHref: vi.fn((to: string) => to),
}))

// Mock navigation hook
vi.mock('../../hooks/navigation/useNavigateWithTransition', () => ({
  useNavigateWithTransition: () => mockNavigate,
}))

describe('TransitionLink', () => {
  beforeEach(() => {
    vi.clearAllMocks()
    // Reset console.warn mock
    vi.spyOn(console, 'warn').mockImplementation(() => {})
  })

  it('renders link with children', () => {
    render(<TransitionLink to="/test-path">Click me</TransitionLink>)

    const link = screen.getByRole('link', {name: /click me/i})
    expect(link).toBeInTheDocument()
  })

  it('sets href attribute for relative paths', () => {
    render(<TransitionLink to="/test-path">Test Link</TransitionLink>)

    const link = screen.getByRole('link')
    expect(link).toHaveAttribute('href', '/test-path')
  })

  it('navigates on click', async () => {
    const user = userEvent.setup()

    render(<TransitionLink to="/test-path">Navigate</TransitionLink>)

    const link = screen.getByRole('link')
    await user.click(link)

    expect(mockNavigate).toHaveBeenCalledWith('/test-path')
  })

  it('prevents default link behavior on click', async () => {
    userEvent.setup()
    const preventDefault = vi.fn()

    render(<TransitionLink to="/test-path">Link</TransitionLink>)

    const link = screen.getByRole('link')

    // Manually create and dispatch event to test preventDefault
    const clickEvent = new MouseEvent('click', {
      bubbles: true,
      cancelable: true,
    })
    Object.defineProperty(clickEvent, 'preventDefault', {
      value: preventDefault,
    })

    link.dispatchEvent(clickEvent)

    expect(preventDefault).toHaveBeenCalled()
  })

  it('calls custom onClick handler', async () => {
    const user = userEvent.setup()
    const handleClick = vi.fn()

    render(
      <TransitionLink to="/test-path" onClick={handleClick}>
        Link
      </TransitionLink>
    )

    const link = screen.getByRole('link')
    await user.click(link)

    expect(handleClick).toHaveBeenCalled()
    expect(mockNavigate).toHaveBeenCalled()
  })

  it('does not navigate if onClick prevents default', async () => {
    const user = userEvent.setup()
    const handleClick = vi.fn(err => err.preventDefault())

    render(
      <TransitionLink to="/test-path" onClick={handleClick}>
        Link
      </TransitionLink>
    )

    const link = screen.getByRole('link')
    await user.click(link)

    expect(handleClick).toHaveBeenCalled()
    expect(mockNavigate).not.toHaveBeenCalled()
  })

  it('warns about absolute URLs', () => {
    const warnSpy = vi.spyOn(console, 'warn')

    render(
      <TransitionLink to="https://example.com">External Link</TransitionLink>
    )

    expect(warnSpy).toHaveBeenCalledWith(
      'TransitionLink: absolute URLs are not supported. Please update to a valid relative path.'
    )
  })

  it('does not set href for absolute URLs', () => {
    render(
      <TransitionLink to="https://example.com">External Link</TransitionLink>
    )

    const link = screen.getByText('External Link')
    expect(link).not.toHaveAttribute('href')
  })

  it('forwards ref to anchor element', () => {
    const ref = vi.fn()

    render(
      <TransitionLink to="/test" ref={ref}>
        Link
      </TransitionLink>
    )

    expect(ref).toHaveBeenCalled()
    expect(ref.mock.calls[0][0]).toBeInstanceOf(HTMLAnchorElement)
  })

  it('passes additional props to anchor element', () => {
    render(
      <TransitionLink
        to="/test"
        className="custom-class"
        data-testid="custom-link"
      >
        Link
      </TransitionLink>
    )

    const link = screen.getByRole('link')
    expect(link).toHaveClass('custom-class')
    expect(link).toHaveAttribute('data-testid', 'custom-link')
  })
})
