import React, { isValidElement } from 'react'
import { describe, expect, it } from 'vitest'
import StatCard from './StatCard'
import type { LucideIcon } from 'lucide-react'

function collectText(node: unknown): string[] {
  if (node === null || node === undefined || typeof node === 'boolean') return []
  if (typeof node === 'string' || typeof node === 'number') return [String(node)]
  if (Array.isArray(node)) return node.flatMap(collectText)
  if (isValidElement<{ children?: React.ReactNode }>(node)) return collectText(node.props.children)
  return []
}

type ElementWithClass = { children?: React.ReactNode; className?: string }

function collectElements(node: unknown): React.ReactElement<ElementWithClass>[] {
  if (node === null || node === undefined || typeof node === 'boolean') return []
  if (Array.isArray(node)) return node.flatMap(collectElements)
  if (!isValidElement<ElementWithClass>(node)) return []
  return [node, ...collectElements(node.props.children)]
}

function FakeIcon(props: { className?: string }) {
  return React.createElement('svg', props)
}

const icon = FakeIcon as unknown as LucideIcon

describe('StatCard', () => {
  it('renders title, numeric value, and positive changes with a plus sign', () => {
    const element = StatCard({ title: 'Revenue', value: 12450, change: 8.238, icon })
    const text = collectText(element)
    const renderedText = text.join('')

    expect(text).toContain('Revenue')
    expect(text).toContain('12450')
    expect(renderedText).toContain('+8.2%')
    expect(text).toContain('vs last month')
  })

  it('renders negative changes without forcing a positive marker', () => {
    const element = StatCard({ title: 'Cancellations', value: '12', change: -3.15, vsLastMonthLabel: 'vs previous period', icon })
    const text = collectText(element)
    const renderedText = text.join('')

    expect(renderedText).toContain('-3.1%')
    expect(text).toContain('vs previous period')
    expect(renderedText).not.toContain('+-3.1')
  })

  it('omits the trend row when no change is provided', () => {
    const element = StatCard({ title: 'Active cars', value: 31, icon })
    const text = collectText(element)

    expect(text).toContain('Active cars')
    expect(text).toContain('31')
    expect(text).not.toContain('vs last month')
    expect(text.join('')).not.toContain('%')
  })

  it('passes custom icon color and background classes to the rendered icon shell', () => {
    const element = StatCard({
      title: 'Fleet',
      value: 9,
      icon,
      iconColor: 'text-violet-700',
      iconBg: 'bg-violet-50',
    })
    const elements = collectElements(element)

    expect(elements.some((node) => String(node.props.className ?? '').includes('bg-violet-50'))).toBe(true)
    expect(elements.some((node) => String(node.props.className ?? '').includes('text-violet-700'))).toBe(true)
  })
})
