import {
  type BackIntent,
  canonicalBack,
  type Intent,
  placeIntents,
} from '../src/components/menu/intents'

describe('placeIntents', () => {
  it('picks a single back intent and drops duplicates', () => {
    const intents: Intent[] = [
      { kind: 'back' },
      { kind: 'back', label: 'Ignored' },
    ]
    const placed = placeIntents(intents)
    expect(placed.back).toBeDefined()
    expect(placed.back?.label).toBeUndefined()
  })

  it('promotes an act with weight primary to commit', () => {
    const intents: Intent[] = [
      {
        kind: 'act',
        id: 'save',
        icon: 'save',
        label: 'Save',
        weight: 'primary',
        onPress: () => {},
      },
    ]
    const placed = placeIntents(intents)
    expect(placed.commit).toBeDefined()
    expect(placed.commit?.id).toBe('save')
    expect(placed.trailing).toHaveLength(0)
  })

  it('demotes trailing acts beyond capacity into the overflow menu', () => {
    const intents: Intent[] = [
      { kind: 'act', id: 'a1', icon: 'edit', label: 'A', onPress: () => {} },
      { kind: 'act', id: 'a2', icon: 'edit', label: 'B', onPress: () => {} },
      { kind: 'act', id: 'a3', icon: 'edit', label: 'C', onPress: () => {} },
      { kind: 'act', id: 'a4', icon: 'edit', label: 'D', onPress: () => {} },
      { kind: 'act', id: 'a5', icon: 'edit', label: 'E', onPress: () => {} },
    ]
    const placed = placeIntents(intents, { barWidthPt: 300 })
    expect(placed.trailing).toHaveLength(1)
    expect(placed.menu?.items).toHaveLength(4)
  })

  it('collapses filter into the menu on narrow bars that also have search', () => {
    const intents: Intent[] = [
      {
        kind: 'filter',
        value: 'a',
        options: [
          { value: 'a', label: 'A' },
          { value: 'b', label: 'B' },
        ],
        onChange: () => {},
      },
      {
        kind: 'search',
        placeholder: 'Search',
        value: '',
        onChangeText: () => {},
      },
    ]
    const placed = placeIntents(intents, { barWidthPt: 320 })
    expect(placed.filter).toBeUndefined()
    expect(placed.menu?.items).toHaveLength(2)
  })

  it('keeps filter and search separate on wide bars', () => {
    const intents: Intent[] = [
      {
        kind: 'filter',
        value: 'a',
        options: [
          { value: 'a', label: 'A' },
          { value: 'b', label: 'B' },
        ],
        onChange: () => {},
      },
      {
        kind: 'search',
        placeholder: 'Search',
        value: '',
        onChangeText: () => {},
      },
    ]
    const placed = placeIntents(intents, { barWidthPt: 480 })
    expect(placed.filter).toBeDefined()
    expect(placed.search).toBeDefined()
    expect(placed.menu).toBeUndefined()
  })
})

describe('canonicalBack', () => {
  const buildDeps = (overrides: Partial<Parameters<typeof canonicalBack>[1]>) => ({
    canGoBack: jest.fn(() => true),
    canDismiss: jest.fn(() => false),
    back: jest.fn(),
    dismiss: jest.fn(),
    replace: jest.fn(),
    fallbackHref: '/(auth)/(tabs)/home' as never,
    ...overrides,
  })

  it('calls onPress override when provided', () => {
    const onPress = jest.fn()
    const intent: BackIntent = { kind: 'back', onPress }
    const deps = buildDeps({})
    canonicalBack(intent, deps)
    expect(onPress).toHaveBeenCalled()
    expect(deps.back).not.toHaveBeenCalled()
  })

  it('dismisses a modal when dismissMode=close and canDismiss=true', () => {
    const intent: BackIntent = { kind: 'back', dismissMode: 'close' }
    const deps = buildDeps({ canDismiss: jest.fn(() => true) })
    canonicalBack(intent, deps)
    expect(deps.dismiss).toHaveBeenCalled()
    expect(deps.back).not.toHaveBeenCalled()
  })

  it('calls back when history exists', () => {
    const intent: BackIntent = { kind: 'back' }
    const deps = buildDeps({})
    canonicalBack(intent, deps)
    expect(deps.back).toHaveBeenCalled()
  })

  it('falls back to replace when no history', () => {
    const intent: BackIntent = { kind: 'back' }
    const deps = buildDeps({ canGoBack: jest.fn(() => false) })
    canonicalBack(intent, deps)
    expect(deps.replace).toHaveBeenCalledWith('/(auth)/(tabs)/home')
  })

  it('uses intent-provided fallbackHref over the default', () => {
    const intent: BackIntent = {
      kind: 'back',
      fallbackHref: '/login' as never,
    }
    const deps = buildDeps({ canGoBack: jest.fn(() => false) })
    canonicalBack(intent, deps)
    expect(deps.replace).toHaveBeenCalledWith('/login')
  })
})
