import { describe, test, expect, beforeEach } from 'vitest'
import { render, screen } from '@testing-library/react'
import { ThemeProvider, createTheme } from '@mui/material/styles'
import { CategoryUI } from './category-ui'
import { useWidgetStore } from '../stores/widget-store'
import type { CategoryWidgetState } from './types'

// Create a test theme with qualitative colors
const testTheme = createTheme({
  palette: {
    primary: {
      main: '#1976d2',
    },
    qualitative: {
      bold: {
        0: '#1f77b4',
        1: '#ff7f0e',
        2: '#2ca02c',
        3: '#d62728',
        4: '#9467bd',
        5: '#8c564b',
        6: '#e377c2',
        7: '#7f7f7f',
      },
    },
  },
})

// Helper function to render with theme
function renderWithTheme(ui: React.ReactElement) {
  return render(<ThemeProvider theme={testTheme}>{ui}</ThemeProvider>)
}

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

  test('returns null when widget does not exist', () => {
    const { container } = renderWithTheme(<CategoryUI id='non-existent' />)
    expect(container.firstChild).toBeNull()
  })

  test('returns null when data is empty', () => {
    useWidgetStore.getState().setWidget<CategoryWidgetState>('test-category', {
      type: 'category',
      data: [[]],
    })

    const { container } = renderWithTheme(<CategoryUI id='test-category' />)
    expect(container.firstChild).toBeNull()
  })

  test('renders basic category data', () => {
    useWidgetStore.getState().setWidget<CategoryWidgetState>('test-category', {
      type: 'category',
      data: [
        [
          { name: 'Category A', value: 100 },
          { name: 'Category B', value: 50 },
        ],
      ],
    })

    renderWithTheme(<CategoryUI id='test-category' />)

    expect(screen.getByText('Category A')).toBeTruthy()
    expect(screen.getByText('Category B')).toBeTruthy()
    expect(screen.getByText('100')).toBeTruthy()
    expect(screen.getByText('50')).toBeTruthy()
  })

  test('auto-calculates max value from data when max prop not provided', () => {
    useWidgetStore.getState().setWidget<CategoryWidgetState>('test-category', {
      type: 'category',
      data: [
        [
          { name: 'Category A', value: 100 },
          { name: 'Category B', value: 150 },
          { name: 'Category C', value: 75 },
        ],
      ],
    })

    renderWithTheme(<CategoryUI id='test-category' />)

    // Verify all categories are rendered
    expect(screen.getByText('Category A')).toBeTruthy()
    expect(screen.getByText('Category B')).toBeTruthy()
    expect(screen.getByText('Category C')).toBeTruthy()
    expect(screen.getByText('100')).toBeTruthy()
    expect(screen.getByText('150')).toBeTruthy()
    expect(screen.getByText('75')).toBeTruthy()
  })

  test('uses custom max value when provided', () => {
    useWidgetStore.getState().setWidget<CategoryWidgetState>('test-category', {
      type: 'category',
      data: [
        [
          { name: 'Category A', value: 100 },
          { name: 'Category B', value: 150 },
        ],
      ],
      max: 200,
    })

    renderWithTheme(<CategoryUI id='test-category' />)

    // Verify categories are rendered with custom max
    expect(screen.getByText('Category A')).toBeTruthy()
    expect(screen.getByText('Category B')).toBeTruthy()
    expect(screen.getByText('100')).toBeTruthy()
    expect(screen.getByText('150')).toBeTruthy()
  })

  test('handles max value of 0', () => {
    useWidgetStore.getState().setWidget<CategoryWidgetState>('test-category', {
      type: 'category',
      data: [
        [
          { name: 'Category A', value: 100 },
          { name: 'Category B', value: 50 },
        ],
      ],
      max: 0,
    })

    renderWithTheme(<CategoryUI id='test-category' />)

    // Verify categories are rendered even with max=0
    expect(screen.getByText('Category A')).toBeTruthy()
    expect(screen.getByText('Category B')).toBeTruthy()
    expect(screen.getByText('100')).toBeTruthy()
    expect(screen.getByText('50')).toBeTruthy()
  })

  test('handles max value less than actual data values', () => {
    useWidgetStore.getState().setWidget<CategoryWidgetState>('test-category', {
      type: 'category',
      data: [
        [
          { name: 'Category A', value: 150 },
          { name: 'Category B', value: 75 },
        ],
      ],
      max: 100,
    })

    renderWithTheme(<CategoryUI id='test-category' />)

    // Verify categories are rendered when values exceed max
    expect(screen.getByText('Category A')).toBeTruthy()
    expect(screen.getByText('Category B')).toBeTruthy()
    expect(screen.getByText('150')).toBeTruthy()
    expect(screen.getByText('75')).toBeTruthy()
  })

  test('uses custom max with multi-series data', () => {
    useWidgetStore.getState().setWidget<CategoryWidgetState>('test-category', {
      type: 'category',
      data: [
        [
          { name: 'Product A', value: 80 },
          { name: 'Product B', value: 60 },
        ],
        [
          { name: 'Product A', value: 90 },
          { name: 'Product B', value: 70 },
        ],
      ],
      max: 100,
      series: [{ name: 'Q1' }, { name: 'Q2' }],
    })

    renderWithTheme(<CategoryUI id='test-category' />)

    // Multi-series should show legend
    expect(screen.getByText('Q1')).toBeTruthy()
    expect(screen.getByText('Q2')).toBeTruthy()

    // Verify product names are displayed
    expect(screen.getByText('Product A')).toBeTruthy()
    expect(screen.getByText('Product B')).toBeTruthy()
  })

  test('updates when max value changes', () => {
    useWidgetStore.getState().setWidget<CategoryWidgetState>('test-category', {
      type: 'category',
      data: [[{ name: 'Category A', value: 100 }]],
      max: 200,
    })

    renderWithTheme(<CategoryUI id='test-category' />)

    expect(screen.getByText('Category A')).toBeTruthy()
    expect(screen.getByText('100')).toBeTruthy()

    // Update max value
    useWidgetStore.getState().setWidget<CategoryWidgetState>('test-category', {
      type: 'category',
      data: [[{ name: 'Category A', value: 100 }]],
      max: 100,
    })

    // Widget should still render after update
    expect(screen.getByText('Category A')).toBeTruthy()
    expect(screen.getByText('100')).toBeTruthy()
  })

  test('uses formatter when provided', () => {
    useWidgetStore.getState().setWidget<CategoryWidgetState>('test-category', {
      type: 'category',
      data: [[{ name: 'Category A', value: 1234 }]],
      formatter: (value: number) => `$${value}`,
    })

    renderWithTheme(<CategoryUI id='test-category' />)

    expect(screen.getByText('$1234')).toBeTruthy()
  })

  test('uses formatter with custom max', () => {
    useWidgetStore.getState().setWidget<CategoryWidgetState>('test-category', {
      type: 'category',
      data: [[{ name: 'Sales', value: 125000 }]],
      max: 200000,
      formatter: (value: number) =>
        new Intl.NumberFormat('en-US', {
          style: 'currency',
          currency: 'USD',
          maximumFractionDigits: 0,
        }).format(value),
    })

    renderWithTheme(<CategoryUI id='test-category' />)

    // Should show formatted value
    expect(screen.getByText('$125,000')).toBeTruthy()
    expect(screen.getByText('Sales')).toBeTruthy()
  })

  test('max prop works with maxItems configuration', () => {
    useWidgetStore.getState().setWidget<CategoryWidgetState>('test-category', {
      type: 'category',
      data: [
        [
          { name: 'Item 1', value: 80 },
          { name: 'Item 2', value: 60 },
          { name: 'Item 3', value: 40 },
          { name: 'Item 4', value: 20 },
        ],
      ],
      max: 100,
      maxItems: 2,
    })

    renderWithTheme(<CategoryUI id='test-category' />)

    // Should show only first 2 items
    expect(screen.getByText('Item 1')).toBeTruthy()
    expect(screen.getByText('Item 2')).toBeTruthy()

    // Should show values
    expect(screen.getByText('80')).toBeTruthy()
    expect(screen.getByText('60')).toBeTruthy()
  })

  describe('Overflow behavior', () => {
    test('applies overflow auto when hiddenCount is 0 (no maxItems)', () => {
      useWidgetStore
        .getState()
        .setWidget<CategoryWidgetState>('test-category', {
          type: 'category',
          data: [
            [
              { name: 'Item 1', value: 100 },
              { name: 'Item 2', value: 50 },
            ],
          ],
          // No maxItems set, so hiddenCount will be 0
        })

      const { container } = renderWithTheme(<CategoryUI id='test-category' />)
      // The list Box has inline style for overflow
      const listBox = container.querySelector<HTMLElement>(
        '[style*="overflow"]',
      )!

      expect(listBox).toBeTruthy()
      expect(listBox.style.overflow).toBe('auto')
    })

    test('applies overflow hidden when hiddenCount is greater than 0', () => {
      useWidgetStore
        .getState()
        .setWidget<CategoryWidgetState>('test-category', {
          type: 'category',
          data: [
            [
              { name: 'Item 1', value: 100 },
              { name: 'Item 2', value: 80 },
              { name: 'Item 3', value: 60 },
              { name: 'Item 4', value: 40 },
            ],
          ],
          maxItems: 2, // This creates hiddenCount = 2
        })

      const { container } = renderWithTheme(<CategoryUI id='test-category' />)
      // The list Box has inline style for overflow
      const listBox = container.querySelector<HTMLElement>(
        '[style*="overflow"]',
      )!

      expect(listBox).toBeTruthy()
      expect(listBox.style.overflow).toBe('hidden')
    })

    test('maintains overflow auto when maxItems equals data length', () => {
      useWidgetStore
        .getState()
        .setWidget<CategoryWidgetState>('test-category', {
          type: 'category',
          data: [
            [
              { name: 'Item 1', value: 100 },
              { name: 'Item 2', value: 50 },
            ],
          ],
          maxItems: 2, // Same as data length, hiddenCount = 0
        })

      const { container } = renderWithTheme(<CategoryUI id='test-category' />)
      // The list Box has inline style for overflow
      const listBox = container.querySelector<HTMLElement>(
        '[style*="overflow"]',
      )!

      expect(listBox).toBeTruthy()
      expect(listBox.style.overflow).toBe('auto')
    })

    test('applies overflow auto when maxItems exceeds data length', () => {
      useWidgetStore
        .getState()
        .setWidget<CategoryWidgetState>('test-category', {
          type: 'category',
          data: [
            [
              { name: 'Item 1', value: 100 },
              { name: 'Item 2', value: 50 },
            ],
          ],
          maxItems: 5, // More than data length, hiddenCount = 0
        })

      const { container } = renderWithTheme(<CategoryUI id='test-category' />)
      // The list Box has inline style for overflow
      const listBox = container.querySelector<HTMLElement>(
        '[style*="overflow"]',
      )!

      expect(listBox).toBeTruthy()
      expect(listBox.style.overflow).toBe('auto')
    })

    test('works correctly with multi-series data', () => {
      useWidgetStore
        .getState()
        .setWidget<CategoryWidgetState>('test-category', {
          type: 'category',
          data: [
            [
              { name: 'Product A', value: 100 },
              { name: 'Product B', value: 80 },
              { name: 'Product C', value: 60 },
            ],
            [
              { name: 'Product A', value: 90 },
              { name: 'Product B', value: 70 },
              { name: 'Product C', value: 50 },
            ],
          ],
          series: [{ name: 'Q1' }, { name: 'Q2' }],
          maxItems: 2, // hiddenCount = 1
        })

      const { container } = renderWithTheme(<CategoryUI id='test-category' />)
      // The list Box has inline style for overflow
      const listBox = container.querySelector<HTMLElement>(
        '[style*="overflow"]',
      )!

      expect(listBox).toBeTruthy()
      expect(listBox.style.overflow).toBe('hidden')
    })
  })
})
