import { describe, test, expect, beforeEach } from 'vitest'
import { render, screen } from '@testing-library/react'
import { Value } from './value'
import { useWidgetStore } from '../../stores/widget-store'
import type { FormulaWidgetState } from '../types'

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

  test('renders value from widget data at default index 0', () => {
    useWidgetStore.getState().setWidget<FormulaWidgetState>('test-value', {
      type: 'formula',
      data: [{ value: 100 }],
    })

    render(<Value id='test-value' />)
    expect(screen.getByText('100')).toBeTruthy()
  })

  test('renders value at specified index', () => {
    useWidgetStore.getState().setWidget<FormulaWidgetState>('test-value', {
      type: 'formula',
      data: [{ value: 100 }, { value: 200 }, { value: 300 }],
    })

    render(<Value id='test-value' index={1} />)
    expect(screen.getByText('200')).toBeTruthy()
  })

  test('renders value at index 0 when index not specified', () => {
    useWidgetStore.getState().setWidget<FormulaWidgetState>('test-value', {
      type: 'formula',
      data: [{ value: 100 }, { value: 200 }],
    })

    render(<Value id='test-value' />)
    expect(screen.getByText('100')).toBeTruthy()
  })

  test('renders zero value', () => {
    useWidgetStore.getState().setWidget<FormulaWidgetState>('test-value', {
      type: 'formula',
      data: [{ value: 0 }],
    })

    render(<Value id='test-value' />)
    expect(screen.getByText('0')).toBeTruthy()
  })

  test('renders negative value', () => {
    useWidgetStore.getState().setWidget<FormulaWidgetState>('test-value', {
      type: 'formula',
      data: [{ value: -100 }],
    })

    render(<Value id='test-value' />)
    expect(screen.getByText('-100')).toBeTruthy()
  })

  test('renders decimal value', () => {
    useWidgetStore.getState().setWidget<FormulaWidgetState>('test-value', {
      type: 'formula',
      data: [{ value: 123.456 }],
    })

    render(<Value id='test-value' />)
    expect(screen.getByText('123.456')).toBeTruthy()
  })

  test('renders large value', () => {
    useWidgetStore.getState().setWidget<FormulaWidgetState>('test-value', {
      type: 'formula',
      data: [{ value: 1000000000 }],
    })

    render(<Value id='test-value' />)
    expect(screen.getByText('1000000000')).toBeTruthy()
  })

  test('applies custom color from data', () => {
    useWidgetStore.getState().setWidget<FormulaWidgetState>('test-value', {
      type: 'formula',
      data: [{ value: 100, color: '#FF0000' }],
    })

    render(<Value id='test-value' />)
    const element = screen.getByText('100')
    expect(element).toBeTruthy()
  })

  test('renders without color when not specified', () => {
    useWidgetStore.getState().setWidget<FormulaWidgetState>('test-value', {
      type: 'formula',
      data: [{ value: 100 }],
    })

    render(<Value id='test-value' />)
    expect(screen.getByText('100')).toBeTruthy()
  })

  test('applies different colors for different items', () => {
    useWidgetStore.getState().setWidget<FormulaWidgetState>('test-value', {
      type: 'formula',
      data: [
        { value: 100, color: '#FF0000' },
        { value: 200, color: '#00FF00' },
      ],
    })

    const { unmount } = render(<Value id='test-value' index={0} />)
    expect(screen.getByText('100')).toBeTruthy()
    unmount()

    render(<Value id='test-value' index={1} />)
    expect(screen.getByText('200')).toBeTruthy()
  })

  test('renders as Typography h5', () => {
    useWidgetStore.getState().setWidget<FormulaWidgetState>('test-value', {
      type: 'formula',
      data: [{ value: 100 }],
    })

    render(<Value id='test-value' />)
    const element = screen.getByText('100')
    expect(element.tagName).toBe('H5')
  })

  test('returns nothing when widget does not exist', () => {
    const { container } = render(<Value id='non-existent' />)
    // Value still renders Item, which renders Typography, but with undefined children
    expect(container.querySelector('.MuiTypography-root')).toBeTruthy()
  })

  test('returns nothing when widget data is undefined', () => {
    useWidgetStore.getState().setWidget<FormulaWidgetState>('test-value', {
      type: 'formula',
    })

    const { container } = render(<Value id='test-value' />)
    // Value still renders Item, which renders Typography, but with undefined children
    expect(container.querySelector('.MuiTypography-root')).toBeTruthy()
  })

  test('returns nothing when index is out of bounds', () => {
    useWidgetStore.getState().setWidget<FormulaWidgetState>('test-value', {
      type: 'formula',
      data: [{ value: 100 }],
    })

    const { container } = render(<Value id='test-value' index={5} />)
    // Value still renders Item, which renders Typography, but with undefined children
    expect(container.querySelector('.MuiTypography-root')).toBeTruthy()
  })

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

    const { container } = render(<Value id='test-value' />)
    // Value still renders Item, which renders Typography, but with undefined children
    expect(container.querySelector('.MuiTypography-root')).toBeTruthy()
  })

  test('passes disabled prop to Item', () => {
    useWidgetStore.getState().setWidget<FormulaWidgetState>('test-value', {
      type: 'formula',
      data: [{ value: 100 }],
    })

    render(<Value id='test-value' disabled={true} />)
    const element = screen.getByText('100')
    expect(element.getAttribute('data-disabled')).toBe('true')
  })

  test('passes TypographyProps to Item', () => {
    useWidgetStore.getState().setWidget<FormulaWidgetState>('test-value', {
      type: 'formula',
      data: [{ value: 100 }],
    })

    render(<Value id='test-value' TypographyProps={{ className: 'custom' }} />)
    const element = screen.getByText('100')
    expect(element.classList.contains('custom')).toBe(true)
  })

  test('merges color from data with TypographyProps', () => {
    useWidgetStore.getState().setWidget<FormulaWidgetState>('test-value', {
      type: 'formula',
      data: [{ value: 100, color: '#FF0000' }],
    })

    render(<Value id='test-value' TypographyProps={{ className: 'custom' }} />)
    const element = screen.getByText('100')
    expect(element.classList.contains('custom')).toBe(true)
  })

  test('color from data is passed to TypographyProps', () => {
    useWidgetStore.getState().setWidget<FormulaWidgetState>('test-value', {
      type: 'formula',
      data: [{ value: 100, color: 'primary' }],
    })

    render(<Value id='test-value' />)
    const element = screen.getByText('100')
    // Color is passed as a prop, not an HTML attribute
    expect(element).toBeTruthy()
  })

  test('handles all data properties together', () => {
    useWidgetStore.getState().setWidget<FormulaWidgetState>('test-value', {
      type: 'formula',
      data: [
        {
          value: 100,
          color: '#FF0000',
          prefix: '$',
          suffix: 'USD',
        },
      ],
    })

    render(<Value id='test-value' />)
    expect(screen.getByText('100')).toBeTruthy()
  })

  test('updates when widget data changes', () => {
    useWidgetStore.getState().setWidget<FormulaWidgetState>('test-value', {
      type: 'formula',
      data: [{ value: 100 }],
    })

    const { rerender } = render(<Value id='test-value' />)
    expect(screen.getByText('100')).toBeTruthy()

    useWidgetStore.getState().setWidget<FormulaWidgetState>('test-value', {
      data: [{ value: 200 }],
    })

    rerender(<Value id='test-value' />)
    expect(screen.queryByText('100')).toBeNull()
    expect(screen.getByText('200')).toBeTruthy()
  })

  test('updates when index changes', () => {
    useWidgetStore.getState().setWidget<FormulaWidgetState>('test-value', {
      type: 'formula',
      data: [{ value: 100 }, { value: 200 }],
    })

    const { rerender } = render(<Value id='test-value' index={0} />)
    expect(screen.getByText('100')).toBeTruthy()

    rerender(<Value id='test-value' index={1} />)
    expect(screen.queryByText('100')).toBeNull()
    expect(screen.getByText('200')).toBeTruthy()
  })

  test('handles widget removal gracefully', () => {
    useWidgetStore.getState().setWidget<FormulaWidgetState>('test-value', {
      type: 'formula',
      data: [{ value: 100 }],
    })

    const { container, rerender } = render(<Value id='test-value' />)
    expect(screen.getByText('100')).toBeTruthy()

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

    rerender(<Value id='test-value' />)
    // Item still renders, but with undefined value
    expect(container.querySelector('.MuiTypography-root')).toBeTruthy()
  })

  test('renders with multiple values at different indices', () => {
    useWidgetStore.getState().setWidget<FormulaWidgetState>('test-value', {
      type: 'formula',
      data: [
        { value: 100 },
        { value: 200 },
        { value: 300 },
        { value: 400 },
        { value: 500 },
      ],
    })

    const { unmount } = render(<Value id='test-value' index={0} />)
    expect(screen.getByText('100')).toBeTruthy()
    unmount()

    render(<Value id='test-value' index={2} />)
    expect(screen.getByText('300')).toBeTruthy()
  })

  test('handles negative index (invalid but should not crash)', () => {
    useWidgetStore.getState().setWidget<FormulaWidgetState>('test-value', {
      type: 'formula',
      data: [{ value: 100 }],
    })

    const { container } = render(<Value id='test-value' index={-1} />)
    // Negative index is invalid, should render undefined
    expect(container.querySelector('.MuiTypography-root')).toBeTruthy()
  })

  test('value with very small decimal', () => {
    useWidgetStore.getState().setWidget<FormulaWidgetState>('test-value', {
      type: 'formula',
      data: [{ value: 0.0001 }],
    })

    render(<Value id='test-value' />)
    expect(screen.getByText('0.0001')).toBeTruthy()
  })

  test('value with scientific notation', () => {
    useWidgetStore.getState().setWidget<FormulaWidgetState>('test-value', {
      type: 'formula',
      data: [{ value: 1e10 }],
    })

    render(<Value id='test-value' />)
    expect(screen.getByText('10000000000')).toBeTruthy()
  })
})
