import { describe, it, expect, beforeEach, afterEach } from 'vitest'
import { fireEvent, render, screen } from '@testing-library/react'
import { Provider } from '../provider/widget-provider'
import { clearAllWidgetStores } from '../stores'
import { Wrapper } from './widget-wrapper'
import { Actions } from './widget-actions'
import { Content } from './widget-content'

beforeEach(() => clearAllWidgetStores())
afterEach(() => clearAllWidgetStores())

function withProvider(id: string, ui: React.ReactNode, isFetching = false) {
  return (
    <Provider id={id} data={[]} isFetching={isFetching}>
      {ui}
    </Provider>
  )
}

describe('<Wrapper>', () => {
  it('renders the title', () => {
    render(
      withProvider(
        'wrap-1',
        <Wrapper title='Sales'>
          <Content>body</Content>
        </Wrapper>,
      ),
    )
    expect(screen.getByText('Sales')).toBeTruthy()
  })

  it('renders Content children when expanded', () => {
    render(
      withProvider(
        'wrap-2',
        <Wrapper title='t'>
          <Content>
            <div data-testid='body'>body</div>
          </Content>
        </Wrapper>,
      ),
    )
    expect(screen.getByTestId('body')).toBeTruthy()
  })

  it('keeps Content mounted but visually hidden when collapsed', () => {
    // Accordion uses MUI <Collapse>, which animates the parent via height/visibility.
    // Children stay mounted (the Collapse keeps `keepMounted` semantics by default).
    render(
      withProvider(
        'wrap-3',
        <Wrapper title='t' defaultCollapsed>
          <Content>
            <div data-testid='body'>body</div>
          </Content>
        </Wrapper>,
      ),
    )
    expect(screen.getByTestId('body')).toBeTruthy()
    // Find the AccordionDetails ancestor and confirm aria-hidden / inert reflects collapsed.
    const root = screen.getByText('t').closest('.MuiAccordion-root')
    expect(root?.getAttribute('data-collapsed')).toBe('true')
  })

  it('toggles via the chevron icon button — header summary owns the click', () => {
    render(
      withProvider(
        'wrap-4',
        <Wrapper title='t'>
          <Content>body</Content>
        </Wrapper>,
      ),
    )
    const summary = screen.getByRole('button', { name: 'Collapse' })
    expect(summary.getAttribute('aria-expanded')).toBe('true')
    fireEvent.click(summary)
    expect(
      screen
        .getByRole('button', { name: 'Expand' })
        .getAttribute('aria-expanded'),
    ).toBe('false')
  })

  it('honors custom collapse/expand labels on the summary', () => {
    render(
      withProvider(
        'wrap-5',
        <Wrapper title='t' labels={{ collapse: 'Hide', expand: 'Show' }}>
          <Content>body</Content>
        </Wrapper>,
      ),
    )
    expect(screen.getByRole('button', { name: 'Hide' })).toBeTruthy()
    fireEvent.click(screen.getByRole('button', { name: 'Hide' }))
    expect(screen.getByRole('button', { name: 'Show' })).toBeTruthy()
  })

  it('renders <Actions> children inside the summary row, not the details panel', () => {
    render(
      withProvider(
        'wrap-6',
        <Wrapper title='t'>
          <Actions>
            <button data-testid='action-btn'>A</button>
          </Actions>
          <Content>
            <div data-testid='body-content'>body</div>
          </Content>
        </Wrapper>,
      ),
    )
    const actionBtn = screen.getByTestId('action-btn')
    const bodyContent = screen.getByTestId('body-content')
    // The action lives inside the AccordionSummary, the body inside AccordionDetails.
    expect(actionBtn.closest('.MuiAccordionSummary-root')).not.toBeNull()
    expect(bodyContent.closest('.MuiAccordionDetails-root')).not.toBeNull()
  })

  it('shows a LinearProgress at the top when the store reports isFetching', () => {
    render(
      withProvider(
        'wrap-7',
        <Wrapper title='t'>
          <Content>body</Content>
        </Wrapper>,
        true,
      ),
    )
    expect(screen.getByRole('progressbar')).toBeTruthy()
  })

  it('hides the LinearProgress when isFetching is false', () => {
    render(
      withProvider(
        'wrap-8',
        <Wrapper title='t'>
          <Content>body</Content>
        </Wrapper>,
        false,
      ),
    )
    expect(screen.queryByRole('progressbar')).toBeNull()
  })

  it('renders by default (elevation variant) with body intact', () => {
    render(
      withProvider(
        'wrap-variant-default',
        <Wrapper title='t'>
          <Content>
            <div data-testid='body'>body</div>
          </Content>
        </Wrapper>,
      ),
    )
    expect(screen.getByText('t')).toBeTruthy()
    expect(screen.getByTestId('body')).toBeTruthy()
  })

  it('renders the outlined variant with body intact', () => {
    render(
      withProvider(
        'wrap-variant-outlined',
        <Wrapper title='t' variant='outlined'>
          <Content>
            <div data-testid='body'>body</div>
          </Content>
        </Wrapper>,
      ),
    )
    expect(screen.getByText('t')).toBeTruthy()
    expect(screen.getByTestId('body')).toBeTruthy()
  })

  it('applies disabled styling without removing children', () => {
    render(
      withProvider(
        'wrap-9',
        <Wrapper title='t' disabled>
          <Content>
            <div data-testid='body'>body</div>
          </Content>
        </Wrapper>,
      ),
    )
    expect(screen.getByTestId('body')).toBeTruthy()
  })

  it('disables only the summary, leaving the details panel interactive', () => {
    let clicks = 0
    render(
      withProvider(
        'wrap-10',
        <Wrapper title='t' disabled>
          <Content>
            <button data-testid='body-btn' onClick={() => (clicks += 1)}>
              click
            </button>
          </Content>
        </Wrapper>,
      ),
    )
    // The details panel keeps its events even while the wrapper is disabled.
    fireEvent.click(screen.getByTestId('body-btn'))
    expect(clicks).toBe(1)
  })

  it('does not toggle when the disabled summary is clicked', () => {
    let lastCollapsed: boolean | undefined
    render(
      withProvider(
        'wrap-11',
        <Wrapper
          title='t'
          disabled
          onCollapseChange={(c) => (lastCollapsed = c)}
        >
          <Content>body</Content>
        </Wrapper>,
      ),
    )
    fireEvent.click(screen.getByText('t'))
    expect(lastCollapsed).toBeUndefined()
  })

  it('keeps summary actions clickable while the wrapper is disabled', () => {
    let actionClicks = 0
    let lastCollapsed: boolean | undefined
    render(
      withProvider(
        'wrap-12',
        <Wrapper
          title='t'
          disabled
          onCollapseChange={(c) => (lastCollapsed = c)}
        >
          <Actions>
            <button
              data-testid='action-btn'
              onClick={() => (actionClicks += 1)}
            >
              A
            </button>
          </Actions>
          <Content>body</Content>
        </Wrapper>,
      ),
    )
    fireEvent.click(screen.getByTestId('action-btn'))
    // The action fires, and clicking it must not toggle the disabled wrapper.
    expect(actionClicks).toBe(1)
    expect(lastCollapsed).toBeUndefined()
  })
})
