import { describe, expect, it } from 'vitest'
import {
  MenuAuthorizationError,
  MenuCycleError,
  MenuDepthExceededError,
  MenuLimitExceededError,
  MenuNotFoundError,
  MenuUrlSchemeError,
  MenuValidationError,
  isMenuAuthorizationError,
  isMenuCycleError,
  isMenuDepthExceededError,
  isMenuLimitExceededError,
  isMenuNotFoundError,
  isMenuUrlSchemeError,
  isMenuValidationError,
} from './errors.js'

/** Simulates a deduped second copy of the same error class (breaks instanceof). */
function duplicate<T extends object>(e: T): T {
  return Object.assign(Object.create(Object.getPrototypeOf(e)), e)
}

describe('menu errors', () => {
  it('carry typed payloads and _tag brands', () => {
    const auth = new MenuAuthorizationError('u1', 'manageMenus')
    expect(auth._tag).toBe('MenuAuthorizationError')
    expect(auth.actorId).toBe('u1')
    expect(auth.action).toBe('manageMenus')

    const notFound = new MenuNotFoundError('menu', 'primary')
    expect(notFound._tag).toBe('MenuNotFoundError')
    expect(notFound.kind).toBe('menu')
    expect(notFound.id).toBe('primary')

    const validation = new MenuValidationError('key', 'invalid menu key')
    expect(validation._tag).toBe('MenuValidationError')
    expect(validation.field).toBe('key')
    expect(validation.detail).toBe('invalid menu key')

    const depth = new MenuDepthExceededError(5)
    expect(depth._tag).toBe('MenuDepthExceededError')
    expect(depth.maxDepth).toBe(5)

    const limit = new MenuLimitExceededError(200)
    expect(limit._tag).toBe('MenuLimitExceededError')
    expect(limit.maxItems).toBe(200)

    const cycle = new MenuCycleError('item-1')
    expect(cycle._tag).toBe('MenuCycleError')
    expect(cycle.itemId).toBe('item-1')

    const scheme = new MenuUrlSchemeError('javascript:alert(1)')
    expect(scheme._tag).toBe('MenuUrlSchemeError')
    expect(scheme.url).toBe('javascript:alert(1)')
  })

  it('structural guards match by _tag across duplicated copies, not instanceof', () => {
    expect(isMenuAuthorizationError(new MenuAuthorizationError('u', 'manageMenus'))).toBe(true)
    expect(isMenuAuthorizationError(duplicate(new MenuAuthorizationError('u', 'manageMenus')))).toBe(true)
    expect(isMenuAuthorizationError({ _tag: 'MenuAuthorizationError', actorId: 'u', action: 'manageMenus' })).toBe(true)
    expect(isMenuAuthorizationError(new Error('x'))).toBe(false)

    expect(isMenuNotFoundError(duplicate(new MenuNotFoundError('item', 'x')))).toBe(true)
    expect(isMenuValidationError(duplicate(new MenuValidationError('k', 'd')))).toBe(true)
    expect(isMenuDepthExceededError(duplicate(new MenuDepthExceededError(5)))).toBe(true)
    expect(isMenuLimitExceededError(duplicate(new MenuLimitExceededError(200)))).toBe(true)
    expect(isMenuCycleError(duplicate(new MenuCycleError('i')))).toBe(true)
    expect(isMenuUrlSchemeError(duplicate(new MenuUrlSchemeError('data:x')))).toBe(true)
  })
})
