import { render, screen, fireEvent } from '@testing-library/react'
import { MetricCard } from '../MetricCard'
import { PipelineFunnel } from '../PipelineFunnel'
import { TopCampaigns } from '../TopCampaigns'
import { SparklineTrend } from '../SparklineTrend'
import { PeriodSelector } from '../PeriodSelector'
import { DashboardGrid } from '../DashboardGrid'
import { DashboardSection } from '../DashboardSection'

// ---------------------------------------------------------------------------
// Shared test helpers
// ---------------------------------------------------------------------------

function MockIcon({ className }: { className?: string }) {
  return <svg data-testid="mock-icon" className={className} />
}

// ---------------------------------------------------------------------------
// MetricCard
// ---------------------------------------------------------------------------

describe('MetricCard', () => {
  const baseProps = {
    label: 'Total Leads',
    value: 1234,
    icon: MockIcon,
  }

  it('renders the label and value', () => {
    render(<MetricCard {...baseProps} />)
    expect(screen.getByText('Total Leads')).toBeInTheDocument()
    expect(screen.getByText('1234')).toBeInTheDocument()
  })

  it('renders string values', () => {
    render(<MetricCard {...baseProps} value="$9,999" />)
    expect(screen.getByText('$9,999')).toBeInTheDocument()
  })

  it('renders the icon', () => {
    render(<MetricCard {...baseProps} />)
    expect(screen.getByTestId('mock-icon')).toBeInTheDocument()
  })

  it('renders "—" while loading', () => {
    render(<MetricCard {...baseProps} isLoading />)
    expect(screen.getByText('—')).toBeInTheDocument()
    expect(screen.queryByText('1234')).not.toBeInTheDocument()
  })

  it('renders "Error" in error state', () => {
    render(<MetricCard {...baseProps} error />)
    expect(screen.getByText('Error')).toBeInTheDocument()
  })

  it('applies animate-pulse class when loading', () => {
    const { container } = render(<MetricCard {...baseProps} isLoading />)
    expect(container.firstChild).toHaveClass('animate-pulse')
  })

  it('applies error border classes when error is true', () => {
    const { container } = render(<MetricCard {...baseProps} error />)
    // The inner content div gets the error classes
    const cardDiv = container.querySelector('.border-red-200')
    expect(cardDiv).toBeInTheDocument()
  })

  describe('trend indicator', () => {
    it('renders positive trend value with + prefix', () => {
      render(<MetricCard {...baseProps} trend={{ value: 12, isPositive: true }} />)
      expect(screen.getByText('+12%')).toBeInTheDocument()
    })

    it('renders negative trend value without + prefix', () => {
      render(<MetricCard {...baseProps} trend={{ value: -5, isPositive: false }} />)
      expect(screen.getByText('-5%')).toBeInTheDocument()
    })

    it('renders neutral trend when isPositive is undefined', () => {
      render(<MetricCard {...baseProps} trend={{ value: 0 }} />)
      expect(screen.getByText('0%')).toBeInTheDocument()
    })

    it('renders positive trend in green', () => {
      render(<MetricCard {...baseProps} trend={{ value: 8, isPositive: true }} />)
      const trendEl = screen.getByText('+8%').closest('div')
      expect(trendEl).toHaveClass('text-green-600')
    })

    it('renders negative trend in red', () => {
      render(<MetricCard {...baseProps} trend={{ value: -3, isPositive: false }} />)
      const trendEl = screen.getByText('-3%').closest('div')
      expect(trendEl).toHaveClass('text-red-600')
    })

    it('renders neutral trend in gray', () => {
      render(<MetricCard {...baseProps} trend={{ value: 0 }} />)
      const trendEl = screen.getByText('0%').closest('div')
      expect(trendEl).toHaveClass('text-gray-500')
    })

    it('renders the trend label', () => {
      render(
        <MetricCard
          {...baseProps}
          trend={{ value: 5, isPositive: true, label: 'vs last month' }}
        />
      )
      expect(screen.getByText('vs last month')).toBeInTheDocument()
    })

    it('hides trend while loading', () => {
      render(
        <MetricCard {...baseProps} trend={{ value: 5, isPositive: true }} isLoading />
      )
      expect(screen.queryByText('+5%')).not.toBeInTheDocument()
    })

    it('hides trend in error state', () => {
      render(
        <MetricCard {...baseProps} trend={{ value: 5, isPositive: true }} error />
      )
      expect(screen.queryByText('+5%')).not.toBeInTheDocument()
    })
  })

  describe('sparkline', () => {
    it('renders sparkline when sparklineData has 2+ points', () => {
      const { container } = render(
        <MetricCard {...baseProps} sparklineData={[10, 20, 15, 30]} />
      )
      expect(container.querySelector('svg')).toBeInTheDocument()
    })

    it('does not render sparkline for a single data point', () => {
      const { container } = render(
        <MetricCard {...baseProps} sparklineData={[10]} />
      )
      // The only svg present might be the icon; sparkline itself returns null for < 2 points
      const svgs = container.querySelectorAll('svg')
      // icon is an svg; sparkline should not add a second one
      expect(svgs.length).toBe(1)
    })

    it('does not render sparkline while loading', () => {
      const { container } = render(
        <MetricCard {...baseProps} sparklineData={[10, 20, 30]} isLoading />
      )
      // Only the mock icon svg should exist (no sparkline)
      const svgs = container.querySelectorAll('svg')
      expect(svgs.length).toBe(1)
    })
  })

  describe('href link', () => {
    it('wraps content in an anchor tag when href is provided', () => {
      render(<MetricCard {...baseProps} href="/leads" />)
      const link = screen.getByRole('link')
      expect(link).toHaveAttribute('href', '/leads')
    })

    it('sets accessible label on the anchor', () => {
      render(<MetricCard {...baseProps} href="/leads" label="Total Leads" />)
      expect(screen.getByRole('link', { name: 'View Total Leads details' })).toBeInTheDocument()
    })

    it('does not render anchor when href is omitted', () => {
      render(<MetricCard {...baseProps} />)
      expect(screen.queryByRole('link')).not.toBeInTheDocument()
    })
  })

  it('applies custom className', () => {
    const { container } = render(<MetricCard {...baseProps} className="custom-class" />)
    const cardDiv = container.querySelector('.custom-class')
    expect(cardDiv).toBeInTheDocument()
  })
})

// ---------------------------------------------------------------------------
// SparklineTrend
// ---------------------------------------------------------------------------

describe('SparklineTrend', () => {
  it('renders an svg with the correct role and aria-label for increasing trend', () => {
    render(<SparklineTrend data={[10, 20, 30]} />)
    const svg = screen.getByRole('img')
    expect(svg).toHaveAttribute('aria-label', 'Trend chart showing increasing pattern')
  })

  it('reports decreasing trend in aria-label', () => {
    render(<SparklineTrend data={[30, 20, 10]} />)
    expect(screen.getByRole('img')).toHaveAttribute(
      'aria-label',
      'Trend chart showing decreasing pattern'
    )
  })

  it('reports stable trend in aria-label', () => {
    render(<SparklineTrend data={[15, 15, 15]} />)
    expect(screen.getByRole('img')).toHaveAttribute(
      'aria-label',
      'Trend chart showing stable pattern'
    )
  })

  it('returns null for a single data point', () => {
    const { container } = render(<SparklineTrend data={[42]} />)
    expect(container.firstChild).toBeNull()
  })

  it('returns null for an empty array', () => {
    const { container } = render(<SparklineTrend data={[]} />)
    expect(container.firstChild).toBeNull()
  })

  it('renders both the line path and the area fill path', () => {
    const { container } = render(<SparklineTrend data={[5, 10, 7, 14]} />)
    const paths = container.querySelectorAll('path')
    // area fill + line stroke = 2 paths
    expect(paths.length).toBe(2)
  })

  it('accepts a hex color directly', () => {
    const { container } = render(<SparklineTrend data={[1, 2, 3]} color="#FF0000" />)
    const linePath = container.querySelectorAll('path')[1]
    expect(linePath).toHaveAttribute('stroke', '#FF0000')
  })

  it('resolves a Tailwind color class to hex', () => {
    const { container } = render(<SparklineTrend data={[1, 2, 3]} color="text-green-500" />)
    const linePath = container.querySelectorAll('path')[1]
    expect(linePath).toHaveAttribute('stroke', '#10B981')
  })

  it('falls back to blue-500 for unknown color keys', () => {
    const { container } = render(<SparklineTrend data={[1, 2, 3]} color="text-unknown-999" />)
    const linePath = container.querySelectorAll('path')[1]
    expect(linePath).toHaveAttribute('stroke', '#3B82F6')
  })

  it('applies custom height', () => {
    const { container } = render(<SparklineTrend data={[1, 2, 3]} height={60} />)
    const svg = container.querySelector('svg')
    expect(svg).toHaveAttribute('height', '60')
  })

  it('applies custom className', () => {
    const { container } = render(
      <SparklineTrend data={[1, 2, 3]} className="my-sparkline" />
    )
    expect(container.querySelector('svg')).toHaveClass('my-sparkline')
  })
})

// ---------------------------------------------------------------------------
// PeriodSelector
// ---------------------------------------------------------------------------

describe('PeriodSelector', () => {
  const onChange = jest.fn()

  beforeEach(() => jest.clearAllMocks())

  it('renders default period buttons', () => {
    render(<PeriodSelector selected="month" onChange={onChange} />)
    expect(screen.getByText('Week')).toBeInTheDocument()
    expect(screen.getByText('Month')).toBeInTheDocument()
    expect(screen.getByText('Quarter')).toBeInTheDocument()
    expect(screen.getByText('Year')).toBeInTheDocument()
  })

  it('marks the selected period button as pressed', () => {
    render(<PeriodSelector selected="quarter" onChange={onChange} />)
    expect(screen.getByText('Quarter')).toHaveAttribute('aria-pressed', 'true')
    expect(screen.getByText('Week')).toHaveAttribute('aria-pressed', 'false')
    expect(screen.getByText('Month')).toHaveAttribute('aria-pressed', 'false')
    expect(screen.getByText('Year')).toHaveAttribute('aria-pressed', 'false')
  })

  it('calls onChange with the correct value on button click', () => {
    render(<PeriodSelector selected="month" onChange={onChange} />)
    fireEvent.click(screen.getByText('Year'))
    expect(onChange).toHaveBeenCalledWith('year')
    expect(onChange).toHaveBeenCalledTimes(1)
  })

  it('calls onChange when the already-selected period is clicked', () => {
    render(<PeriodSelector selected="month" onChange={onChange} />)
    fireEvent.click(screen.getByText('Month'))
    expect(onChange).toHaveBeenCalledWith('month')
  })

  it('renders custom periods', () => {
    const custom = [
      { value: 'day', label: 'Day' },
      { value: 'week', label: 'Week' },
    ]
    render(<PeriodSelector periods={custom} selected="day" onChange={onChange} />)
    expect(screen.getByText('Day')).toBeInTheDocument()
    expect(screen.getByText('Week')).toBeInTheDocument()
    expect(screen.queryByText('Month')).not.toBeInTheDocument()
  })

  it('has role="group" with accessible label', () => {
    const { container } = render(<PeriodSelector selected="month" onChange={onChange} />)
    const group = container.querySelector('[role="group"]')
    expect(group).toBeInTheDocument()
    expect(group).toHaveAttribute('aria-label', 'Time period')
  })

  it('applies custom className to the wrapper', () => {
    const { container } = render(
      <PeriodSelector selected="week" onChange={onChange} className="my-selector" />
    )
    expect(container.firstChild).toHaveClass('my-selector')
  })

  it('applies active style class only to selected button', () => {
    render(<PeriodSelector selected="week" onChange={onChange} />)
    const weekBtn = screen.getByText('Week')
    const monthBtn = screen.getByText('Month')
    expect(weekBtn).toHaveClass('bg-primary/15')
    expect(monthBtn).not.toHaveClass('bg-primary/15')
  })
})

// ---------------------------------------------------------------------------
// PipelineFunnel
// ---------------------------------------------------------------------------

describe('PipelineFunnel', () => {
  const stages = [
    { stage: 'Lead', count: 200 },
    { stage: 'Qualified', count: 100 },
    { stage: 'Proposal', count: 50 },
    { stage: 'Closed', count: 20 },
  ]

  it('renders the default title', () => {
    render(<PipelineFunnel stages={stages} />)
    expect(screen.getByText('Pipeline Funnel')).toBeInTheDocument()
  })

  it('renders a custom title', () => {
    render(<PipelineFunnel stages={stages} title="Sales Funnel" />)
    expect(screen.getByText('Sales Funnel')).toBeInTheDocument()
  })

  it('renders all stage names', () => {
    render(<PipelineFunnel stages={stages} />)
    expect(screen.getByText('Lead')).toBeInTheDocument()
    expect(screen.getByText('Qualified')).toBeInTheDocument()
    expect(screen.getByText('Proposal')).toBeInTheDocument()
    expect(screen.getByText('Closed')).toBeInTheDocument()
  })

  it('renders stage counts with locale formatting', () => {
    const bigStages = [
      { stage: 'Top', count: 1000 },
      { stage: 'Mid', count: 500 },
    ]
    render(<PipelineFunnel stages={bigStages} />)
    expect(screen.getByText('1,000')).toBeInTheDocument()
    expect(screen.getByText('500')).toBeInTheDocument()
  })

  it('shows "% of total" relative to the first stage', () => {
    render(<PipelineFunnel stages={stages} />)
    // First stage = 200, second = 100 → 50%, third = 50 → 25%, last = 20 → 10%
    expect(screen.getByText('100% of total')).toBeInTheDocument()
    expect(screen.getByText('50% of total')).toBeInTheDocument()
    expect(screen.getByText('25% of total')).toBeInTheDocument()
    expect(screen.getByText('10% of total')).toBeInTheDocument()
  })

  it('renders the overall conversion footer when there are 2+ stages', () => {
    render(<PipelineFunnel stages={stages} />)
    expect(screen.getByText('Overall Conversion')).toBeInTheDocument()
    // The footer span contains "10%" directly followed by the route span "(Lead → Closed)"
    // Use getAllByText and check one matches the bold footer element specifically
    const tenPctMatches = screen.getAllByText(/10%/)
    // At least one match must be the bold footer span (not the "% of total" span)
    const footerMatch = tenPctMatches.find(
      el => !el.textContent?.includes('of total')
    )
    expect(footerMatch).toBeTruthy()
    expect(screen.getByText(/Lead → Closed/)).toBeInTheDocument()
  })

  it('does not render overall conversion footer with a single stage', () => {
    render(<PipelineFunnel stages={[{ stage: 'Only', count: 50 }]} />)
    expect(screen.queryByText('Overall Conversion')).not.toBeInTheDocument()
  })

  it('renders empty state when stages is an empty array', () => {
    render(<PipelineFunnel stages={[]} />)
    expect(screen.getByText('No pipeline data available')).toBeInTheDocument()
  })

  it('renders empty state title even in empty state', () => {
    render(<PipelineFunnel stages={[]} title="My Funnel" />)
    expect(screen.getByText('My Funnel')).toBeInTheDocument()
  })

  it('renders stage list with role="list"', () => {
    render(<PipelineFunnel stages={stages} />)
    expect(screen.getByRole('list', { name: 'Pipeline stages' })).toBeInTheDocument()
  })

  it('renders each stage as a listitem', () => {
    render(<PipelineFunnel stages={stages} />)
    expect(screen.getAllByRole('listitem')).toHaveLength(stages.length)
  })

  it('renders bar buttons with accessible labels', () => {
    render(<PipelineFunnel stages={stages} />)
    const leadBtn = screen.getByRole('button', {
      name: 'Lead: 200 prospects, 100% of total',
    })
    expect(leadBtn).toBeInTheDocument()
  })

  it('calls onStageClick with stage name when a bar is clicked', () => {
    const onStageClick = jest.fn()
    render(<PipelineFunnel stages={stages} onStageClick={onStageClick} />)
    // Click the listitem div wrapping the 'Qualified' stage
    const listitems = screen.getAllByRole('listitem')
    fireEvent.click(listitems[1])
    expect(onStageClick).toHaveBeenCalledWith('Qualified')
    expect(onStageClick).toHaveBeenCalledTimes(1)
  })

  it('disables bar buttons when onStageClick is not provided', () => {
    render(<PipelineFunnel stages={stages} />)
    const buttons = screen.getAllByRole('button')
    buttons.forEach(btn => expect(btn).toBeDisabled())
  })

  it('enables bar buttons when onStageClick is provided', () => {
    render(<PipelineFunnel stages={stages} onStageClick={jest.fn()} />)
    const buttons = screen.getAllByRole('button')
    buttons.forEach(btn => expect(btn).not.toBeDisabled())
  })

  it('handles stages with zero counts without crashing', () => {
    const zeroStages = [
      { stage: 'Lead', count: 0 },
      { stage: 'Closed', count: 0 },
    ]
    render(<PipelineFunnel stages={zeroStages} />)
    expect(screen.getByText('Lead')).toBeInTheDocument()
    expect(screen.getByText('Overall Conversion')).toBeInTheDocument()
  })
})

// ---------------------------------------------------------------------------
// TopCampaigns
// ---------------------------------------------------------------------------

describe('TopCampaigns', () => {
  const campaigns = [
    { id: '1', name: 'Spring Launch', engagementRate: 80, status: 'active' as const },
    { id: '2', name: 'Summer Sale', engagementRate: 55, status: 'paused' as const },
    { id: '3', name: 'Fall Promo', engagementRate: 30, status: 'completed' as const },
    { id: '4', name: 'Winter Deal', engagementRate: 15 },
    { id: '5', name: 'Holiday Push', engagementRate: 70, status: 'active' as const },
    { id: '6', name: 'Extra Campaign', engagementRate: 40, status: 'active' as const },
  ]

  it('renders the default title', () => {
    render(<TopCampaigns campaigns={campaigns} />)
    expect(screen.getByText('Top Performing Campaigns')).toBeInTheDocument()
  })

  it('renders a custom title', () => {
    render(<TopCampaigns campaigns={campaigns} title="Best Campaigns" />)
    expect(screen.getByText('Best Campaigns')).toBeInTheDocument()
  })

  it('shows empty state when campaigns array is empty', () => {
    render(<TopCampaigns campaigns={[]} />)
    expect(screen.getByText('No campaigns yet')).toBeInTheDocument()
    expect(
      screen.getByText('Launch your first campaign to see performance metrics')
    ).toBeInTheDocument()
  })

  it('renders empty state title in empty state', () => {
    render(<TopCampaigns campaigns={[]} title="My Campaigns" />)
    expect(screen.getByText('My Campaigns')).toBeInTheDocument()
  })

  it('limits display to maxItems (default 5)', () => {
    render(<TopCampaigns campaigns={campaigns} />)
    // 6 campaigns but only 5 should appear
    expect(screen.queryByText('Extra Campaign')).not.toBeInTheDocument()
    expect(screen.getByText('Spring Launch')).toBeInTheDocument()
    expect(screen.getByText('Holiday Push')).toBeInTheDocument()
  })

  it('respects a custom maxItems value', () => {
    render(<TopCampaigns campaigns={campaigns} maxItems={2} />)
    expect(screen.getByText('Spring Launch')).toBeInTheDocument()
    expect(screen.getByText('Summer Sale')).toBeInTheDocument()
    expect(screen.queryByText('Fall Promo')).not.toBeInTheDocument()
  })

  it('renders rank numbers starting at 1', () => {
    render(<TopCampaigns campaigns={campaigns} />)
    expect(screen.getByText('1')).toBeInTheDocument()
    expect(screen.getByText('2')).toBeInTheDocument()
    expect(screen.getByText('3')).toBeInTheDocument()
  })

  it('renders engagement rates as percentages', () => {
    render(<TopCampaigns campaigns={campaigns} />)
    expect(screen.getByText('80%')).toBeInTheDocument()
    expect(screen.getByText('55%')).toBeInTheDocument()
  })

  it('renders progress bars with correct aria attributes', () => {
    render(<TopCampaigns campaigns={campaigns} />)
    const progressBars = screen.getAllByRole('progressbar')
    expect(progressBars[0]).toHaveAttribute('aria-valuenow', '80')
    expect(progressBars[0]).toHaveAttribute('aria-valuemin', '0')
    expect(progressBars[0]).toHaveAttribute('aria-valuemax', '100')
    expect(progressBars[0]).toHaveAttribute(
      'aria-label',
      'Spring Launch engagement rate: 80%'
    )
  })

  it('renders campaign status badges', () => {
    render(<TopCampaigns campaigns={campaigns} />)
    // Two campaigns have 'active' status within the first 5 (Spring Launch + Holiday Push)
    const activebadges = screen.getAllByText('active')
    expect(activebadges.length).toBeGreaterThanOrEqual(1)
    expect(screen.getByText('paused')).toBeInTheDocument()
    expect(screen.getByText('completed')).toBeInTheDocument()
  })

  it('does not render a status badge when status is omitted', () => {
    const noBadge = [{ id: '1', name: 'No Status', engagementRate: 50 }]
    render(<TopCampaigns campaigns={noBadge} />)
    // Only one listitem, no status span expected
    expect(screen.queryByText('active')).not.toBeInTheDocument()
    expect(screen.queryByText('paused')).not.toBeInTheDocument()
  })

  it('renders the list with role and aria-label', () => {
    render(<TopCampaigns campaigns={campaigns} />)
    expect(
      screen.getByRole('list', { name: 'Top campaigns by engagement' })
    ).toBeInTheDocument()
  })

  it('renders each campaign as a listitem', () => {
    render(<TopCampaigns campaigns={campaigns} />)
    // maxItems defaults to 5
    expect(screen.getAllByRole('listitem')).toHaveLength(5)
  })

  it('shows average engagement footer', () => {
    const simple = [
      { id: '1', name: 'A', engagementRate: 40 },
      { id: '2', name: 'B', engagementRate: 60 },
    ]
    render(<TopCampaigns campaigns={simple} />)
    expect(screen.getByText('Average Engagement')).toBeInTheDocument()
    expect(screen.getByText('50%')).toBeInTheDocument()
  })

  describe('View all button', () => {
    it('shows "View all" when onViewAll is provided AND campaigns exceed maxItems', () => {
      render(
        <TopCampaigns campaigns={campaigns} maxItems={5} onViewAll={jest.fn()} />
      )
      expect(screen.getByText('View all')).toBeInTheDocument()
    })

    it('does not show "View all" when campaigns do not exceed maxItems', () => {
      render(
        <TopCampaigns campaigns={campaigns.slice(0, 3)} maxItems={5} onViewAll={jest.fn()} />
      )
      expect(screen.queryByText('View all')).not.toBeInTheDocument()
    })

    it('does not show "View all" when onViewAll is not provided', () => {
      render(<TopCampaigns campaigns={campaigns} maxItems={5} />)
      expect(screen.queryByText('View all')).not.toBeInTheDocument()
    })

    it('calls onViewAll when "View all" button is clicked', () => {
      const onViewAll = jest.fn()
      render(<TopCampaigns campaigns={campaigns} maxItems={5} onViewAll={onViewAll} />)
      fireEvent.click(screen.getByText('View all'))
      expect(onViewAll).toHaveBeenCalledTimes(1)
    })
  })

  describe('progress bar color thresholds', () => {
    it('applies success color for engagement >= 75', () => {
      const { container } = render(
        <TopCampaigns campaigns={[{ id: '1', name: 'High', engagementRate: 80 }]} />
      )
      const bar = container.querySelector('[role="progressbar"]')
      expect(bar).toHaveClass('bg-success-500')
    })

    it('applies primary color for engagement >= 50 and < 75', () => {
      const { container } = render(
        <TopCampaigns campaigns={[{ id: '1', name: 'Mid', engagementRate: 60 }]} />
      )
      const bar = container.querySelector('[role="progressbar"]')
      expect(bar).toHaveClass('bg-primary')
    })

    it('applies warning color for engagement >= 25 and < 50', () => {
      const { container } = render(
        <TopCampaigns campaigns={[{ id: '1', name: 'Low', engagementRate: 30 }]} />
      )
      const bar = container.querySelector('[role="progressbar"]')
      expect(bar).toHaveClass('bg-warning-500')
    })

    it('applies gray color for engagement < 25', () => {
      const { container } = render(
        <TopCampaigns campaigns={[{ id: '1', name: 'VeryLow', engagementRate: 10 }]} />
      )
      const bar = container.querySelector('[role="progressbar"]')
      expect(bar).toHaveClass('bg-gray-400')
    })
  })
})

// ---------------------------------------------------------------------------
// DashboardGrid
// ---------------------------------------------------------------------------

describe('DashboardGrid', () => {
  it('renders children', () => {
    render(
      <DashboardGrid>
        <div data-testid="child-a">A</div>
        <div data-testid="child-b">B</div>
      </DashboardGrid>
    )
    expect(screen.getByTestId('child-a')).toBeInTheDocument()
    expect(screen.getByTestId('child-b')).toBeInTheDocument()
  })

  it('defaults to 2 columns and md gap', () => {
    const { container } = render(<DashboardGrid><div /></DashboardGrid>)
    const grid = container.firstChild as HTMLElement
    expect(grid).toHaveClass('lg:grid-cols-2')
    expect(grid).toHaveClass('gap-6')
  })

  it('applies lg:grid-cols-1 when columns=1', () => {
    const { container } = render(<DashboardGrid columns={1}><div /></DashboardGrid>)
    expect(container.firstChild).toHaveClass('lg:grid-cols-1')
  })

  it('applies lg:grid-cols-3 when columns=3', () => {
    const { container } = render(<DashboardGrid columns={3}><div /></DashboardGrid>)
    expect(container.firstChild).toHaveClass('lg:grid-cols-3')
  })

  it('applies sm:grid-cols-2 and lg:grid-cols-4 when columns=4', () => {
    const { container } = render(<DashboardGrid columns={4}><div /></DashboardGrid>)
    const grid = container.firstChild as HTMLElement
    expect(grid).toHaveClass('sm:grid-cols-2')
    expect(grid).toHaveClass('lg:grid-cols-4')
  })

  it('applies gap-4 for gap="sm"', () => {
    const { container } = render(<DashboardGrid gap="sm"><div /></DashboardGrid>)
    expect(container.firstChild).toHaveClass('gap-4')
  })

  it('applies gap-8 for gap="lg"', () => {
    const { container } = render(<DashboardGrid gap="lg"><div /></DashboardGrid>)
    expect(container.firstChild).toHaveClass('gap-8')
  })

  it('always has grid-cols-1 as the base class', () => {
    const { container } = render(<DashboardGrid><div /></DashboardGrid>)
    expect(container.firstChild).toHaveClass('grid-cols-1')
  })

  it('applies a custom className', () => {
    const { container } = render(
      <DashboardGrid className="my-grid"><div /></DashboardGrid>
    )
    expect(container.firstChild).toHaveClass('my-grid')
  })
})

// ---------------------------------------------------------------------------
// DashboardSection
// ---------------------------------------------------------------------------

describe('DashboardSection', () => {
  it('renders the title', () => {
    render(<DashboardSection title="Overview"><div /></DashboardSection>)
    expect(screen.getByText('Overview')).toBeInTheDocument()
  })

  it('renders children', () => {
    render(
      <DashboardSection title="Overview">
        <p data-testid="content">Content here</p>
      </DashboardSection>
    )
    expect(screen.getByTestId('content')).toBeInTheDocument()
  })

  it('renders description when provided', () => {
    render(
      <DashboardSection title="Overview" description="A summary of key metrics">
        <div />
      </DashboardSection>
    )
    expect(screen.getByText('A summary of key metrics')).toBeInTheDocument()
  })

  it('does not render description when omitted', () => {
    const { container } = render(
      <DashboardSection title="Overview"><div /></DashboardSection>
    )
    expect(container.querySelector('p')).not.toBeInTheDocument()
  })

  it('renders action node when provided', () => {
    render(
      <DashboardSection
        title="Overview"
        action={<button data-testid="action-btn">Export</button>}
      >
        <div />
      </DashboardSection>
    )
    expect(screen.getByTestId('action-btn')).toBeInTheDocument()
  })

  it('does not render the action wrapper when action is omitted', () => {
    const { container } = render(
      <DashboardSection title="Overview"><div /></DashboardSection>
    )
    // The action wrapper div has class flex-shrink-0
    expect(container.querySelector('.flex-shrink-0')).not.toBeInTheDocument()
  })

  it('renders the title as an h2 element', () => {
    render(<DashboardSection title="My Section"><div /></DashboardSection>)
    expect(screen.getByRole('heading', { level: 2, name: 'My Section' })).toBeInTheDocument()
  })

  it('applies custom className', () => {
    const { container } = render(
      <DashboardSection title="Overview" className="my-section">
        <div />
      </DashboardSection>
    )
    expect(container.firstChild).toHaveClass('my-section')
  })

  it('still renders correctly with all props provided', () => {
    render(
      <DashboardSection
        title="Full Section"
        description="Detailed description"
        action={<button>Action</button>}
        className="full-class"
      >
        <span data-testid="slot">Slot content</span>
      </DashboardSection>
    )
    expect(screen.getByText('Full Section')).toBeInTheDocument()
    expect(screen.getByText('Detailed description')).toBeInTheDocument()
    expect(screen.getByText('Action')).toBeInTheDocument()
    expect(screen.getByTestId('slot')).toBeInTheDocument()
  })
})
