import { render, screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { RulesConfiguration } from './RulesConfiguration'
import { DEFAULT_RULES } from '../types/rules'
import type { NuzlockeRules } from '../types/rules'

function setup(overrides: Partial<React.ComponentProps<typeof RulesConfiguration>> = {}) {
  const props = {
    rules: { ...DEFAULT_RULES },
    onChange: vi.fn(),
    ...overrides,
  }
  render(<RulesConfiguration {...props} />)
  return props
}

describe('RulesConfiguration', () => {
  it('renders all rule section headings', () => {
    setup()
    expect(screen.getByText('Core Rules')).toBeInTheDocument()
    expect(screen.getByText('Playstyle')).toBeInTheDocument()
    expect(screen.getByText('Run Variant')).toBeInTheDocument()
    expect(screen.getByText('Type Restriction')).toBeInTheDocument()
  })

  it('renders the enabled/total count', () => {
    setup()
    expect(screen.getByText(/\d+ of \d+ rules enabled/)).toBeInTheDocument()
  })

  it('renders the Reset to Default button', () => {
    setup()
    expect(screen.getByRole('button', { name: /reset to default/i })).toBeInTheDocument()
  })

  it('calls onChange with updated rules when a rule is toggled off', async () => {
    const { onChange } = setup()
    // RuleToggle renders a role="switch" with no accessible name; navigate
    // to it via the sibling label text.
    const label = screen.getByText('Duplicates Clause')
    // Structure: span → .flex.items-center.gap-2 → .flex-1.pr-4 → row div → switch button
    const switchEl = label
      .closest('div[class]')
      ?.parentElement?.parentElement?.querySelector('[role="switch"]') as HTMLElement
    await userEvent.click(switchEl)
    expect(onChange).toHaveBeenCalledWith(expect.objectContaining({ duplicatesClause: false }))
  })

  it('calls onChange with DEFAULT_RULES when Reset to Default is clicked', async () => {
    const { onChange } = setup({ rules: { ...DEFAULT_RULES, duplicatesClause: false } })
    await userEvent.click(screen.getByRole('button', { name: /reset to default/i }))
    expect(onChange).toHaveBeenCalledWith(DEFAULT_RULES)
  })

  it('calls onReset when Reset to Default is clicked', async () => {
    const onReset = vi.fn()
    setup({ onReset })
    await userEvent.click(screen.getByRole('button', { name: /reset to default/i }))
    expect(onReset).toHaveBeenCalledOnce()
  })

  it('toggles a type on when a type button is clicked', async () => {
    const { onChange } = setup()
    await userEvent.click(screen.getByRole('button', { name: /fire/i }))
    expect(onChange).toHaveBeenCalledWith(expect.objectContaining({ allowedTypes: ['fire'] }))
  })

  it('shows Clear selection button when types are selected', () => {
    setup({ rules: { ...DEFAULT_RULES, allowedTypes: ['fire'] } })
    expect(screen.getByRole('button', { name: /clear selection/i })).toBeInTheDocument()
  })

  it('clears selected types when Clear selection is clicked', async () => {
    const { onChange } = setup({ rules: { ...DEFAULT_RULES, allowedTypes: ['fire', 'water'] } })
    await userEvent.click(screen.getByRole('button', { name: /clear selection/i }))
    expect(onChange).toHaveBeenCalledWith(expect.objectContaining({ allowedTypes: [] }))
  })

  it('hides rules in the hiddenRules set', () => {
    const hiddenRules = new Set<keyof NuzlockeRules>(['duplicatesClause'])
    setup({ hiddenRules })
    expect(screen.queryByText('Duplicates Clause')).not.toBeInTheDocument()
  })
})
