import { describe, test, expect, beforeEach } from 'vitest'
import { render, screen } from '@testing-library/react'
import { SpreadUI } from './spread-ui'
import { useWidgetStore } from '../stores/widget-store'
import type { SpreadWidgetState } from './types'

describe('SpreadUI', () => {
  beforeEach(() => {
    useWidgetStore.getState().clearWidgets()
  })

  test('renders empty container when widget does not exist', () => {
    const { container } = render(<SpreadUI id='non-existent' />)
    // Box wrapper is rendered but Row returns null for missing widget
    expect(container.firstChild?.childNodes.length).toBe(0)
  })

  test('renders with single spread data item', () => {
    useWidgetStore.getState().setWidget<SpreadWidgetState>('test-spread', {
      type: 'spread',
      data: [{ min: 2.1, max: 2.23, suffix: '€' }],
    })

    render(<SpreadUI id='test-spread' />)

    expect(screen.getByText('2.1')).toBeTruthy()
    expect(screen.getByText('-')).toBeTruthy()
    expect(screen.getByText('2.23')).toBeTruthy()
    expect(screen.getByText('€')).toBeTruthy()
  })

  test('renders with multiple spread data items', () => {
    useWidgetStore.getState().setWidget<SpreadWidgetState>('test-spread', {
      type: 'spread',
      data: [
        { min: 1.5, max: 2.5, prefix: '$' },
        { min: 100, max: 200, suffix: '%' },
        { min: 0, max: 10 },
      ],
    })

    render(<SpreadUI id='test-spread' />)

    expect(screen.getByText('$')).toBeTruthy()
    expect(screen.getByText('1.5')).toBeTruthy()
    expect(screen.getByText('2.5')).toBeTruthy()
    expect(screen.getByText('100')).toBeTruthy()
    expect(screen.getByText('200')).toBeTruthy()
    expect(screen.getByText('%')).toBeTruthy()
    expect(screen.getByText('0')).toBeTruthy()
    expect(screen.getByText('10')).toBeTruthy()
  })

  test('renders prefix for each item', () => {
    useWidgetStore.getState().setWidget<SpreadWidgetState>('test-spread', {
      type: 'spread',
      data: [
        { min: 1, max: 10, prefix: 'Range 1:' },
        { min: 20, max: 30, prefix: 'Range 2:' },
      ],
    })

    render(<SpreadUI id='test-spread' />)

    expect(screen.getByText('Range 1:')).toBeTruthy()
    expect(screen.getByText('Range 2:')).toBeTruthy()
  })

  test('renders separator between min and max values', () => {
    useWidgetStore.getState().setWidget<SpreadWidgetState>('test-spread', {
      type: 'spread',
      data: [{ min: 5, max: 15 }],
    })

    render(<SpreadUI id='test-spread' />)

    // Check for separator "-"
    const separators = screen.getAllByText('-')
    expect(separators.length).toBe(1)
  })

  test('renders in correct order: Prefix, MinValue, Separator, MaxValue, Suffix', () => {
    useWidgetStore.getState().setWidget<SpreadWidgetState>('test-spread', {
      type: 'spread',
      data: [{ min: 10, max: 20, prefix: '$', suffix: 'USD' }],
    })

    const { container } = render(<SpreadUI id='test-spread' />)

    const items = container.querySelectorAll('.MuiTypography-root')
    expect(items.length).toBe(5)
    expect(items[0]?.textContent).toBe('$')
    expect(items[1]?.textContent).toBe('10')
    expect(items[2]?.textContent).toBe('-')
    expect(items[3]?.textContent).toBe('20')
    expect(items[4]?.textContent).toBe('USD')
  })

  test('handles data without prefix', () => {
    useWidgetStore.getState().setWidget<SpreadWidgetState>('test-spread', {
      type: 'spread',
      data: [{ min: 5, max: 15, suffix: 'km' }],
    })

    render(<SpreadUI id='test-spread' />)

    expect(screen.getByText('5')).toBeTruthy()
    expect(screen.getByText('-')).toBeTruthy()
    expect(screen.getByText('15')).toBeTruthy()
    expect(screen.getByText('km')).toBeTruthy()
  })

  test('handles data without suffix', () => {
    useWidgetStore.getState().setWidget<SpreadWidgetState>('test-spread', {
      type: 'spread',
      data: [{ min: 5, max: 15, prefix: '$' }],
    })

    render(<SpreadUI id='test-spread' />)

    expect(screen.getByText('$')).toBeTruthy()
    expect(screen.getByText('5')).toBeTruthy()
    expect(screen.getByText('-')).toBeTruthy()
    expect(screen.getByText('15')).toBeTruthy()
  })

  test('handles data with only min and max values', () => {
    useWidgetStore.getState().setWidget<SpreadWidgetState>('test-spread', {
      type: 'spread',
      data: [{ min: 5, max: 15 }],
    })

    render(<SpreadUI id='test-spread' />)

    expect(screen.getByText('5')).toBeTruthy()
    expect(screen.getByText('-')).toBeTruthy()
    expect(screen.getByText('15')).toBeTruthy()
  })

  test('handles empty data array', () => {
    useWidgetStore.getState().setWidget<SpreadWidgetState>('test-spread', {
      type: 'spread',
      data: [],
    })

    const { container } = render(<SpreadUI id='test-spread' />)

    // Row component returns null for empty data, Box wrapper still rendered
    expect(container.firstChild?.childNodes.length).toBe(0)
  })

  test('handles undefined data', () => {
    useWidgetStore.getState().setWidget<SpreadWidgetState>('test-spread', {
      type: 'spread',
    })

    const { container } = render(<SpreadUI id='test-spread' />)

    // Row component returns null for undefined data, Box wrapper still rendered
    expect(container.firstChild?.childNodes.length).toBe(0)
  })

  test('renders with data containing colors', () => {
    useWidgetStore.getState().setWidget<SpreadWidgetState>('test-spread', {
      type: 'spread',
      data: [
        { min: 1, max: 10, color: '#FF0000' },
        { min: 20, max: 30, color: '#00FF00' },
      ],
    })

    render(<SpreadUI id='test-spread' />)

    expect(screen.getByText('1')).toBeTruthy()
    expect(screen.getByText('10')).toBeTruthy()
    expect(screen.getByText('20')).toBeTruthy()
    expect(screen.getByText('30')).toBeTruthy()
  })

  test('renders with negative min value', () => {
    useWidgetStore.getState().setWidget<SpreadWidgetState>('test-spread', {
      type: 'spread',
      data: [{ min: -10, max: 5 }],
    })

    render(<SpreadUI id='test-spread' />)

    expect(screen.getByText('-10')).toBeTruthy()
    expect(screen.getByText('-')).toBeTruthy()
    expect(screen.getByText('5')).toBeTruthy()
  })

  test('renders with zero values', () => {
    useWidgetStore.getState().setWidget<SpreadWidgetState>('test-spread', {
      type: 'spread',
      data: [{ min: 0, max: 0 }],
    })

    render(<SpreadUI id='test-spread' />)

    const zeros = screen.getAllByText('0')
    expect(zeros.length).toBe(2) // min and max both are 0
  })

  test('renders with decimal values', () => {
    useWidgetStore.getState().setWidget<SpreadWidgetState>('test-spread', {
      type: 'spread',
      data: [{ min: 2.1, max: 2.23, suffix: '€' }],
    })

    render(<SpreadUI id='test-spread' />)

    expect(screen.getByText('2.1')).toBeTruthy()
    expect(screen.getByText('2.23')).toBeTruthy()
    expect(screen.getByText('€')).toBeTruthy()
  })

  test('renders with large values', () => {
    useWidgetStore.getState().setWidget<SpreadWidgetState>('test-spread', {
      type: 'spread',
      data: [{ min: 1000000, max: 2000000, prefix: '$' }],
    })

    render(<SpreadUI id='test-spread' />)

    expect(screen.getByText('$')).toBeTruthy()
    expect(screen.getByText('1000000')).toBeTruthy()
    expect(screen.getByText('2000000')).toBeTruthy()
  })

  test('updates when widget data changes', () => {
    useWidgetStore.getState().setWidget<SpreadWidgetState>('test-spread', {
      type: 'spread',
      data: [{ min: 1, max: 10 }],
    })

    const { rerender } = render(<SpreadUI id='test-spread' />)
    expect(screen.getByText('1')).toBeTruthy()
    expect(screen.getByText('10')).toBeTruthy()

    useWidgetStore.getState().setWidget<SpreadWidgetState>('test-spread', {
      data: [{ min: 20, max: 30 }],
    })

    rerender(<SpreadUI id='test-spread' />)
    expect(screen.queryByText('1')).toBeNull()
    expect(screen.queryByText('10')).toBeNull()
    expect(screen.getByText('20')).toBeTruthy()
    expect(screen.getByText('30')).toBeTruthy()
  })

  test('handles widget removal gracefully', () => {
    useWidgetStore.getState().setWidget<SpreadWidgetState>('test-spread', {
      type: 'spread',
      data: [{ min: 1, max: 10 }],
    })

    const { container, rerender } = render(<SpreadUI id='test-spread' />)
    expect(screen.getByText('1')).toBeTruthy()

    useWidgetStore.getState().removeWidget('test-spread')

    rerender(<SpreadUI id='test-spread' />)
    // Box wrapper still rendered but Row returns null
    expect(container.firstChild?.childNodes.length).toBe(0)
  })

  test('renders multiple rows for multiple data items', () => {
    useWidgetStore.getState().setWidget<SpreadWidgetState>('test-spread', {
      type: 'spread',
      data: [
        { min: 1, max: 10, prefix: 'A' },
        { min: 20, max: 30, prefix: 'B' },
        { min: 40, max: 50, prefix: 'C' },
      ],
    })

    const { container } = render(<SpreadUI id='test-spread' />)

    // Each data item should create a row
    const rows = container.querySelectorAll('[class*="MuiBox-root"]')
    expect(rows.length).toBeGreaterThan(0)
  })

  test('renders with series configuration', () => {
    useWidgetStore.getState().setWidget<SpreadWidgetState>('test-spread', {
      type: 'spread',
      data: [{ min: 10, max: 100, suffix: '€' }],
      series: [{ name: 'Revenue', color: '#FF5733' }],
    })

    render(<SpreadUI id='test-spread' />)

    // Series should display the first letter of the name
    expect(screen.getByText('R')).toBeTruthy()
    expect(screen.getByText('10')).toBeTruthy()
    expect(screen.getByText('100')).toBeTruthy()
    expect(screen.getByText('€')).toBeTruthy()
  })

  test('renders without series when not provided', () => {
    useWidgetStore.getState().setWidget<SpreadWidgetState>('test-spread', {
      type: 'spread',
      data: [{ min: 5, max: 25 }],
    })

    const { container } = render(<SpreadUI id='test-spread' />)

    // Should not have any Avatar elements (series)
    const avatars = container.querySelectorAll('.MuiAvatar-root')
    expect(avatars.length).toBe(0)
  })

  test('renders series with default color when color not provided', () => {
    useWidgetStore.getState().setWidget<SpreadWidgetState>('test-spread', {
      type: 'spread',
      data: [{ min: 0, max: 50 }],
      series: [{ name: 'Test' }],
    })

    render(<SpreadUI id='test-spread' />)

    // Series should display the first letter
    expect(screen.getByText('T')).toBeTruthy()
  })

  test('renders with array of series matching data indices', () => {
    useWidgetStore.getState().setWidget<SpreadWidgetState>('test-spread', {
      type: 'spread',
      data: [
        { min: 10, max: 100 },
        { min: 20, max: 200 },
        { min: 30, max: 300 },
      ],
      series: [
        { name: 'Alpha', color: '#FF0000' },
        { name: 'Beta', color: '#00FF00' },
        { name: 'Gamma', color: '#0000FF' },
      ],
    })

    render(<SpreadUI id='test-spread' />)

    // Each series should display its first letter
    expect(screen.getByText('A')).toBeTruthy()
    expect(screen.getByText('B')).toBeTruthy()
    expect(screen.getByText('G')).toBeTruthy()
  })

  test('renders partial series array - only shows series for available indices', () => {
    useWidgetStore.getState().setWidget<SpreadWidgetState>('test-spread', {
      type: 'spread',
      data: [
        { min: 10, max: 100 },
        { min: 20, max: 200 },
        { min: 30, max: 300 },
      ],
      series: [{ name: 'Only First', color: '#FF0000' }],
    })

    const { container } = render(<SpreadUI id='test-spread' />)

    // Only one series avatar should be rendered
    const avatars = container.querySelectorAll('.MuiAvatar-root')
    expect(avatars.length).toBe(1)
    expect(screen.getByText('O')).toBeTruthy()
  })
})
