import '@testing-library/jest-dom'

import { render, screen } from '@testing-library/react'
import { axe, toHaveNoViolations } from 'jest-axe'

import { Truncate, TruncateContext } from './Truncate'

expect.extend(toHaveNoViolations)

describe('Truncate', () => {
  test('renders a short filename as a single span with no tail', () => {
    const { container } = render(<Truncate tail={5}>file.txt</Truncate>)

    const first = container.querySelector('[data-pkt-truncate-part="first"]')
    const tail = container.querySelector('[data-pkt-truncate-part="tail"]')

    expect(first).toHaveTextContent('file.txt')
    expect(tail).toBeNull() // no split when filename is not longer than tail + 3
  })

  test('splits a long filename into head + tail spans that reconstruct the original', () => {
    const name = 'very-long-filename-that-needs-truncation.txt'
    const { container } = render(<Truncate tail={3}>{name}</Truncate>)

    const head = container.querySelector('[data-pkt-truncate-part="first"]')
    const tail = container.querySelector('[data-pkt-truncate-part="tail"]')

    expect(head).toHaveTextContent(name.slice(0, name.length - 3))
    expect(tail).toHaveTextContent('txt')
    expect((head?.textContent ?? '') + (tail?.textContent ?? '')).toBe(name)
  })

  test('defaults to a tail of 5 characters', () => {
    const { container } = render(<Truncate>very-long-filename.txt</Truncate>)

    const tail = container.querySelector('[data-pkt-truncate-part="tail"]')
    expect(tail).toHaveTextContent('e.txt')
  })

  test('takes the tail prop over the context default', () => {
    const { container } = render(
      <TruncateContext.Provider value={{ tail: 10 }}>
        <Truncate tail={3}>very-long-filename.txt</Truncate>
      </TruncateContext.Provider>,
    )

    const tail = container.querySelector('[data-pkt-truncate-part="tail"]')
    expect(tail).toHaveTextContent('txt')
  })

  test('uses the context tail when no prop is given', () => {
    const { container } = render(
      <TruncateContext.Provider value={{ tail: 4 }}>
        <Truncate>very-long-filename.txt</Truncate>
      </TruncateContext.Provider>,
    )

    const tail = container.querySelector('[data-pkt-truncate-part="tail"]')
    expect(tail).toHaveTextContent('.txt')
  })

  test('does not split when the filename is exactly `tail + 3` characters', () => {
    const { container } = render(<Truncate tail={5}>{'12345678'}</Truncate>)

    const head = container.querySelector('[data-pkt-truncate-part="first"]')
    const tail = container.querySelector('[data-pkt-truncate-part="tail"]')

    expect(head).toHaveTextContent('12345678')
    expect(tail).toBeNull()
  })

  test('does not split when tail is 0 or undefined', () => {
    const { container: zero } = render(<Truncate tail={0}>very-long-filename.txt</Truncate>)
    expect(zero.querySelector('[data-pkt-truncate-part="tail"]')).toBeNull()

    const { container: none } = render(
      <TruncateContext.Provider value={{ tail: undefined }}>
        <Truncate>very-long-filename.txt</Truncate>
      </TruncateContext.Provider>,
    )
    expect(none.querySelector('[data-pkt-truncate-part="tail"]')).toBeNull()
  })

  test('handles an empty string', () => {
    const { container } = render(<Truncate>{''}</Truncate>)

    const first = container.querySelector('[data-pkt-truncate-part="first"]')
    expect(first).toHaveTextContent('')
    expect(container.querySelector('[data-pkt-truncate-part="tail"]')).toBeNull()
  })

  describe('accessibility', () => {
    test('has no wcag violations for a short filename', async () => {
      const { container } = render(<Truncate>filename.txt</Truncate>)
      const results = await axe(container)
      expect(results).toHaveNoViolations()
    })

    test('has no wcag violations for a split filename — both head and tail are readable text', async () => {
      const { container } = render(
        <Truncate>very-long-filename-that-definitely-needs-truncation.txt</Truncate>,
      )
      const results = await axe(container)
      expect(results).toHaveNoViolations()

      // head + tail together equal the original, so screen readers read the full name.
      const head = screen.getByText(/very-long-filename-that-definitely-needs-trunc/)
      const tail = screen.getByText('n.txt')
      expect((head.textContent ?? '') + (tail.textContent ?? '')).toBe(
        'very-long-filename-that-definitely-needs-truncation.txt',
      )
    })
  })
})
