import { describe, test, expect, vi, beforeEach } from 'vitest'
import { render, screen, fireEvent } from '@testing-library/react'
import { WidgetWrapper } from './wrapper'
import { useWidgetStore } from '../stores/widget-store'
import type { WrapperState } from './types'

describe('WidgetWrapper', () => {
  beforeEach(() => {
    useWidgetStore.getState().clearWidgets()
    // Pre-set the widget in the store with required base fields
    useWidgetStore.getState().setWidget<WrapperState>('test-wrapper', {
      type: 'wrapper',
      title: 'Test Title',
      isLoading: false,
      visible: true,
      collapsed: false,
      disabled: false,
    })
  })

  const defaultProps = {
    id: 'test-wrapper',
    title: 'Test Title',
    children: <div>Test Content</div>,
  }

  test('renders correctly with default props', () => {
    render(<WidgetWrapper {...defaultProps} />)
    expect(screen.getByText('Test Content')).toBeTruthy()
  })

  test('initializes widget state in store', () => {
    render(<WidgetWrapper {...defaultProps} />)

    const widget = useWidgetStore.getState().widgets[
      'test-wrapper'
    ] as WrapperState
    expect(widget).toBeTruthy()
    expect(widget.id).toBe('test-wrapper')
    expect(widget.title).toBe('Test Title')
    expect(widget.isLoading).toBe(false)
    // collapsed and disabled are set via props, undefined when not passed
    expect(widget.collapsed).toBeUndefined()
    expect(widget.disabled).toBeUndefined()
    expect(widget.visible).toBe(true)
  })

  test('updates widget state when props change', () => {
    // Render with Title 1
    const { rerender } = render(
      <WidgetWrapper {...defaultProps} title='Title 1' />,
    )

    let widget = useWidgetStore.getState().widgets[
      'test-wrapper'
    ] as WrapperState
    expect(widget.title).toBe('Title 1')

    // Rerender with Title 2
    rerender(<WidgetWrapper {...defaultProps} title='Title 2' />)

    widget = useWidgetStore.getState().widgets['test-wrapper'] as WrapperState
    expect(widget.title).toBe('Title 2')
  })

  test('initializes with collapsed state', () => {
    render(<WidgetWrapper {...defaultProps} defaultCollapsed={true} />)

    const widget = useWidgetStore.getState().widgets[
      'test-wrapper'
    ] as WrapperState
    expect(widget.collapsed).toBe(true)
  })

  test('initializes with disabled state', () => {
    render(<WidgetWrapper {...defaultProps} disabled={true} />)

    const widget = useWidgetStore.getState().widgets[
      'test-wrapper'
    ] as WrapperState
    expect(widget.disabled).toBe(true)
  })

  test('initializes with isLoading state', () => {
    useWidgetStore
      .getState()
      .setWidget<WrapperState>('test-wrapper', { isLoading: true })
    render(<WidgetWrapper {...defaultProps} />)

    const widget = useWidgetStore.getState().widgets[
      'test-wrapper'
    ] as WrapperState
    expect(widget.isLoading).toBe(true)
  })

  test('handles collapse toggle correctly', () => {
    const onChangeCollapsed = vi.fn()
    useWidgetStore
      .getState()
      .setWidget<WrapperState>('test-wrapper', { collapsed: false })
    render(
      <WidgetWrapper {...defaultProps} onChangeCollapsed={onChangeCollapsed} />,
    )

    // Find the accordion and click to collapse
    const accordion = screen.getByRole('button')
    fireEvent.click(accordion)

    expect(onChangeCollapsed).toHaveBeenCalledTimes(1)
    const widget = useWidgetStore.getState().widgets[
      'test-wrapper'
    ] as WrapperState
    expect(widget.collapsed).toBe(true)
  })

  test('handles expand correctly', () => {
    const onChangeCollapsed = vi.fn()
    render(
      <WidgetWrapper
        {...defaultProps}
        defaultCollapsed={true}
        onChangeCollapsed={onChangeCollapsed}
      />,
    )

    const accordion = screen.getByRole('button')
    fireEvent.click(accordion)

    expect(onChangeCollapsed).toHaveBeenCalledTimes(1)
    const widget = useWidgetStore.getState().widgets[
      'test-wrapper'
    ] as WrapperState
    expect(widget.collapsed).toBe(false)
  })

  test('returns null when widget is not in store', () => {
    // Clear the store to simulate widget not being set
    const { container } = render(<WidgetWrapper {...defaultProps} />)

    // Force the widget to be removed
    useWidgetStore.getState().removeWidget('test-wrapper')

    // Re-render to trigger the null check
    render(
      <WidgetWrapper id='non-existent-widget' title='Non-existent'>
        <div>Content</div>
      </WidgetWrapper>,
    )

    // The component should render initially
    expect(container).toBeTruthy()
  })

  test('passes sx prop to WrapperUI', () => {
    const sx = { backgroundColor: 'red' }
    render(<WidgetWrapper {...defaultProps} sx={sx} />)

    // Component should render (sx is passed through)
    expect(screen.getByText('Test Content')).toBeTruthy()
  })

  test('passes actions to WrapperUI', () => {
    const actions = [<button key='action1'>Action 1</button>]
    render(<WidgetWrapper {...defaultProps} actions={actions} />)

    expect(screen.getByText('Action 1')).toBeTruthy()
  })

  test('passes options to WrapperUI', () => {
    const options = [
      {
        label: 'Option 1',
        onClick: vi.fn(),
      },
    ]
    render(<WidgetWrapper {...defaultProps} options={options} />)

    // Options button should be rendered
    const optionsButton = screen.getByLabelText('Options')
    expect(optionsButton).toBeTruthy()
  })

  test('passes labels to WrapperUI', () => {
    const labels = {
      options: {
        title: 'Custom Options',
      },
    }
    render(<WidgetWrapper {...defaultProps} labels={labels} />)

    // Component should render with labels
    expect(screen.getByText('Test Content')).toBeTruthy()
  })

  test('updates widget when all props change', () => {
    useWidgetStore.getState().setWidget<WrapperState>('test-wrapper', {
      title: 'Initial Title',
      collapsed: false,
      disabled: false,
      isLoading: false,
    })
    const { rerender } = render(<WidgetWrapper {...defaultProps} />)

    useWidgetStore.getState().setWidget<WrapperState>('test-wrapper', {
      title: 'Updated Title',
      collapsed: true,
      disabled: true,
      isLoading: true,
    })
    rerender(<WidgetWrapper {...defaultProps} />)

    const widget = useWidgetStore.getState().widgets[
      'test-wrapper'
    ] as WrapperState
    expect(widget.title).toBe('Updated Title')
    expect(widget.collapsed).toBe(true)
    expect(widget.disabled).toBe(true)
    expect(widget.isLoading).toBe(true)
  })

  test('handles missing optional props', () => {
    render(
      <WidgetWrapper id='test-wrapper' title='Test Title'>
        <div>Content</div>
      </WidgetWrapper>,
    )

    const widget = useWidgetStore.getState().widgets[
      'test-wrapper'
    ] as WrapperState
    expect(widget.isLoading).toBe(false)
    // collapsed and disabled are set via props, undefined when not passed
    expect(widget.collapsed).toBeUndefined()
    expect(widget.disabled).toBeUndefined()
  })

  test('renders WrapperUI with accordion', () => {
    render(<WidgetWrapper {...defaultProps} />)

    // Should render WrapperUI with accordion
    const accordion = screen.getByRole('button')
    expect(accordion).toBeTruthy()
    expect(screen.getByText('Test Content')).toBeTruthy()
  })

  test('reads title from store when widget exists', () => {
    // Pre-populate store with widget
    useWidgetStore.getState().setWidget<WrapperState>('test-wrapper', {
      type: 'wrapper',
      title: 'Store Title',
      isLoading: false,
      visible: true,
    })

    render(
      <WidgetWrapper id='test-wrapper' title='Store Title'>
        <div>Content</div>
      </WidgetWrapper>,
    )

    // Should display title from store
    const widget = useWidgetStore.getState().widgets[
      'test-wrapper'
    ] as WrapperState
    expect(widget.title).toBe('Store Title')
  })

  test('renders actions even when widget is collapsed', () => {
    const actions = [<button key='action1'>Action 1</button>]
    useWidgetStore
      .getState()
      .setWidget<WrapperState>('test-wrapper', { collapsed: true })
    render(<WidgetWrapper {...defaultProps} actions={actions} />)

    // Actions are visible in the AccordionSummary even when collapsed
    expect(screen.getByText('Action 1')).toBeTruthy()
  })

  test('shows actions when widget is expanded', () => {
    const actions = [<button key='action1'>Action 1</button>]
    useWidgetStore
      .getState()
      .setWidget<WrapperState>('test-wrapper', { collapsed: false })
    render(<WidgetWrapper {...defaultProps} actions={actions} />)

    // Actions should be visible when expanded
    expect(screen.getByText('Action 1')).toBeTruthy()
  })

  test('actions remain visible when collapsing/expanding', () => {
    const actions = [<button key='action1'>Action 1</button>]
    useWidgetStore
      .getState()
      .setWidget<WrapperState>('test-wrapper', { collapsed: false })
    const { rerender } = render(
      <WidgetWrapper {...defaultProps} actions={actions} />,
    )

    // Actions visible when expanded
    expect(screen.getByText('Action 1')).toBeTruthy()

    // Collapse the widget
    useWidgetStore
      .getState()
      .setWidget<WrapperState>('test-wrapper', { collapsed: true })
    rerender(<WidgetWrapper {...defaultProps} actions={actions} />)

    // Actions remain visible when collapsed (in AccordionSummary)
    expect(screen.getByText('Action 1')).toBeTruthy()
  })

  test('isLoading state is independent from other states', () => {
    useWidgetStore
      .getState()
      .setWidget<WrapperState>('test-wrapper', { isLoading: true })
    render(<WidgetWrapper {...defaultProps} />)

    const widget = useWidgetStore.getState().widgets[
      'test-wrapper'
    ] as WrapperState

    // isLoading in store
    expect(widget.isLoading).toBe(true)
  })

  test('updates isLoading when state changes', () => {
    useWidgetStore
      .getState()
      .setWidget<WrapperState>('test-wrapper', { isLoading: false })
    const { rerender } = render(<WidgetWrapper {...defaultProps} />)

    let widget = useWidgetStore.getState().widgets[
      'test-wrapper'
    ] as WrapperState
    expect(widget.isLoading).toBe(false)

    useWidgetStore
      .getState()
      .setWidget<WrapperState>('test-wrapper', { isLoading: true })
    rerender(<WidgetWrapper {...defaultProps} />)

    widget = useWidgetStore.getState().widgets['test-wrapper'] as WrapperState
    expect(widget.isLoading).toBe(true)
  })

  test('widget state persists across re-renders', () => {
    const { rerender } = render(
      <WidgetWrapper {...defaultProps} title='Persistent Title' />,
    )

    const widgetBefore = useWidgetStore.getState().widgets[
      'test-wrapper'
    ] as WrapperState
    expect(widgetBefore.title).toBe('Persistent Title')

    // Re-render without changing props
    rerender(<WidgetWrapper {...defaultProps} title='Persistent Title' />)

    const widgetAfter = useWidgetStore.getState().widgets[
      'test-wrapper'
    ] as WrapperState
    expect(widgetAfter.title).toBe('Persistent Title')
    expect(widgetAfter).toBeTruthy()
  })
})
