import { describe, expect, it } from 'vitest'
import {
  ImmutableFieldError,
  NoPriceForCurrencyError,
  ProductValidationError,
  isImmutableFieldError,
  isNoPriceForCurrencyError,
  isProductValidationError,
} from './errors.js'

describe('commerce-catalog error guards — structural, instanceof-free', () => {
  const cases = [
    {
      guard: isProductValidationError,
      error: new ProductValidationError('slug', 'invalid'),
      code: 'PRODUCT_VALIDATION',
      name: 'ProductValidationError',
      crossRealm: { name: 'ProductValidationError', code: 'PRODUCT_VALIDATION', field: 'slug' },
    },
    {
      guard: isNoPriceForCurrencyError,
      error: new NoPriceForCurrencyError('EUR'),
      code: 'NO_PRICE_FOR_CURRENCY',
      name: 'NoPriceForCurrencyError',
      crossRealm: { name: 'NoPriceForCurrencyError', code: 'NO_PRICE_FOR_CURRENCY', currency: 'EUR' },
    },
    {
      guard: isImmutableFieldError,
      error: new ImmutableFieldError('vendorId'),
      code: 'IMMUTABLE_FIELD',
      name: 'ImmutableFieldError',
      crossRealm: { name: 'ImmutableFieldError', code: 'IMMUTABLE_FIELD', field: 'vendorId' },
    },
  ] as const

  for (const { guard, error, code, name, crossRealm } of cases) {
    it(`${name} guard accepts its own error`, () => {
      expect(guard(error)).toBe(true)
      expect(error.code).toBe(code)
    })

    it(`${name} guard rejects plain object, different error, and wrong cross-realm shape`, () => {
      expect(guard({ field: 'slug' })).toBe(false)
      expect(guard(new Error('plain'))).toBe(false)
      expect(guard(null)).toBe(false)

      const other = cases.find((c) => c.name !== name)!
      expect(guard(other.error)).toBe(false)

      expect(guard({ name, code: 'WRONG_CODE' })).toBe(false)
      expect(guard({ name: 'OtherError', code })).toBe(false)
    })

    it(`${name} guard accepts cross-realm structural shape`, () => {
      expect(guard(crossRealm)).toBe(true)
    })
  }

  it('ImmutableFieldError carries the discriminant .field for each frozen field', () => {
    const kind = new ImmutableFieldError('kind')
    const vendor = new ImmutableFieldError('vendorId')
    expect(kind.field).toBe('kind')
    expect(vendor.field).toBe('vendorId')
    expect(kind.message).toContain('kind')
    expect(vendor.message).toContain('vendorId')
    expect(isImmutableFieldError(kind)).toBe(true)
    expect(isImmutableFieldError(vendor)).toBe(true)
  })
})
