import { cleanup, render, screen, within } from '@testing-library/react'
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'

import { CmsRouteProvider, type CmsRouteData } from '@/spa/cmsRoute'
import Participation from '@/spa/pages/Participation'

const viewport = vi.hoisted(() => ({ mobile: false }))

vi.mock('@/spa/hooks/useIsMobile', () => ({
  useIsMobile: () => viewport.mobile,
}))

vi.mock('next/navigation', () => ({
  usePathname: () => '/teilnahme',
  useRouter: () => ({ push: vi.fn(), replace: vi.fn() }),
}))

vi.mock('@/spa/components/WegZurAuszeichnungSection', () => ({
  default: () => <section data-testid="timeline-stub" />,
}))

vi.mock('@/spa/components/AwardsGridSection', () => ({
  default: () => <section data-testid="awards-stub" />,
}))

vi.mock('@/spa/components/forms/ApplicationFormSection', () => ({
  ApplicationFormSection: () => <section data-testid="application-form-stub" />,
}))

vi.mock('@/spa/components/ui/UnoptimizedImage', () => ({
  default: ({ alt }: { alt: string }) => <div role="img" aria-label={alt} />,
}))

const participationRoute: CmsRouteData = {
  collection: 'pages',
  doc: {
    id: 'participation-page',
    slug: 'teilnahme',
    spaPath: '/teilnahme',
    participation: {
      eligibility: {
        eyebrow: 'CMS eligibility eyebrow',
        heading: 'CMS ELIGIBILITY\nHEADING',
        description: 'CMS eligibility introduction.',
        primaryCta: { label: 'CMS eligibility CTA', url: '/kontakt' },
        criteria: [
          {
            num: 'A',
            title: 'First CMS criterion',
            body: 'First CMS criterion body.',
            icon: 'mapPin',
          },
          {
            num: 'B',
            title: 'Second CMS criterion',
            body: 'Second CMS criterion body.',
            icon: 'users',
          },
        ],
        notes: [
          { title: 'First CMS note', body: 'First CMS note body.', icon: 'building2' },
          { title: 'Second CMS note', body: 'Second CMS note body.', icon: 'userCheck' },
        ],
        nudgeText: 'CMS eligibility conclusion.',
      },
      datesBanner: {
        heading: 'CMS important dates',
        description: 'CMS dates description.',
        mobileItems: [{ date: 'Mobile date', label: 'Mobile label' }],
        desktopItems: [{ date: 'Desktop date', label: 'Desktop label' }],
      },
    },
  },
}

const renderParticipation = () =>
  render(
    <CmsRouteProvider value={participationRoute}>
      <Participation />
    </CmsRouteProvider>,
  )

describe('participation eligibility hierarchy', () => {
  beforeEach(() => {
    viewport.mobile = false
  })

  afterEach(() => cleanup())

  it('keeps CMS eligibility content and its CTA authoritative inside semantic groups', () => {
    renderParticipation()

    const section = screen.getByTestId('eligibility-section')
    const criteria = within(section).getAllByTestId('eligibility-criterion')
    const notes = within(section).getAllByTestId('eligibility-note')
    const cta = within(section).getByRole('link', { name: 'CMS eligibility CTA' })

    expect(within(section).getByRole('heading', { level: 2 }).textContent).toBe(
      'CMS ELIGIBILITYHEADING',
    )
    expect(within(section).getByText('CMS eligibility introduction.')).toBeTruthy()
    expect(criteria.map((row) => row.textContent)).toEqual([
      'AFirst CMS criterionFirst CMS criterion body.',
      'BSecond CMS criterionSecond CMS criterion body.',
    ])
    expect(criteria.every((row) => row.tagName === 'LI')).toBe(true)
    expect(criteria[0]?.parentElement?.tagName).toBe('OL')
    expect(notes.map((note) => note.textContent)).toEqual([
      'First CMS noteFirst CMS note body.',
      'Second CMS noteSecond CMS note body.',
    ])
    expect(within(section).getByText('CMS eligibility conclusion.')).toBeTruthy()
    expect(cta.getAttribute('href')).toBe('/kontakt')
    expect(within(section).getAllByRole('link')).toHaveLength(1)
  })

  it('provides restrained group and dates-transition hooks on desktop', () => {
    renderParticipation()

    expect(screen.getByTestId('eligibility-header').style.background).toBe('rgb(255, 255, 255)')
    expect(screen.getByTestId('eligibility-criteria-group').style.background).toBe(
      'rgb(244, 246, 248)',
    )
    expect(screen.getByTestId('eligibility-summary').style.background).toBe('rgb(17, 29, 85)')
    expect(screen.getByTestId('important-dates-transition').style.borderTopWidth).toBe('8px')
    expect(screen.getByRole('heading', { name: 'CMS important dates', level: 3 })).toBeTruthy()
    expect(screen.getByText('Desktop date')).toBeTruthy()
    expect(screen.queryByText('Mobile date')).toBeNull()
  })

  it('keeps criteria, notes, and conclusion in a single readable mobile order', () => {
    viewport.mobile = true
    renderParticipation()

    const section = screen.getByTestId('eligibility-section')
    const criteriaGroup = within(section).getByTestId('eligibility-criteria-group')
    const notesGroup = within(section).getByTestId('eligibility-notes-group')
    const summary = within(section).getByTestId('eligibility-summary')
    const rows = within(criteriaGroup).getAllByTestId('eligibility-criterion')

    expect(rows.map((row) => row.getAttribute('data-order'))).toEqual(['1', '2'])
    expect(rows.every((row) => row.style.gridTemplateColumns === '40px 1fr')).toBe(true)
    expect(
      criteriaGroup.compareDocumentPosition(notesGroup) & Node.DOCUMENT_POSITION_FOLLOWING,
    ).toBeTruthy()
    expect(
      notesGroup.compareDocumentPosition(summary) & Node.DOCUMENT_POSITION_FOLLOWING,
    ).toBeTruthy()
    expect(screen.getByTestId('important-dates-transition').style.borderTopWidth).toBe('5px')
    expect(screen.getByTestId('important-date-item').getAttribute('data-order')).toBe('1')
    expect(screen.getByTestId('important-date-item').style.gridTemplateColumns).toBe(
      'minmax(112px, 0.9fr) minmax(0, 1.1fr)',
    )
    expect(screen.getByText('Mobile date')).toBeTruthy()
    expect(screen.queryByText('Desktop date')).toBeNull()
  })
})
