/**
 * @module tests/unit/db/stableEqual
 * @description Unit proof for the key-order-insensitive deep-equal that
 * {@link Brainy.diff} uses to decide whether an id present at both endpoints
 * actually changed. The risk it guards: a naive JSON.stringify comparison is
 * key-order-sensitive and would report a no-op re-write as `modified`.
 */
import { describe, it, expect } from 'vitest'
import { stableDeepEqual } from '../../../src/db/stableEqual.js'

describe('stableDeepEqual', () => {
  it('ignores object key order (the core diff requirement)', () => {
    expect(stableDeepEqual({ a: 1, b: 2 }, { b: 2, a: 1 })).toBe(true)
    expect(stableDeepEqual({ a: 1, b: 2, c: { x: 1, y: 2 } }, { c: { y: 2, x: 1 }, b: 2, a: 1 })).toBe(true)
  })

  it('honors array order (arrays are order-significant)', () => {
    expect(stableDeepEqual([1, 2, 3], [1, 2, 3])).toBe(true)
    expect(stableDeepEqual([1, 2, 3], [3, 2, 1])).toBe(false)
    expect(stableDeepEqual([1, 2], [1, 2, 3])).toBe(false)
  })

  it('recurses into nested objects and arrays', () => {
    expect(
      stableDeepEqual(
        { tags: ['a', 'b'], meta: { n: 1, deep: { z: [1, { q: 2 }] } } },
        { meta: { deep: { z: [1, { q: 2 }] }, n: 1 }, tags: ['a', 'b'] }
      )
    ).toBe(true)
    expect(
      stableDeepEqual({ meta: { deep: { z: [1, { q: 2 }] } } }, { meta: { deep: { z: [1, { q: 3 }] } } })
    ).toBe(false)
  })

  it('distinguishes primitives, null, and types', () => {
    expect(stableDeepEqual(1, 1)).toBe(true)
    expect(stableDeepEqual(1, '1')).toBe(false)
    expect(stableDeepEqual(null, null)).toBe(true)
    expect(stableDeepEqual(null, {})).toBe(false)
    expect(stableDeepEqual({ a: 1 }, { a: 1, b: undefined })).toBe(false) // extra key
    expect(stableDeepEqual(true, false)).toBe(false)
  })

  it('treats NaN as equal to NaN (stable value comparison)', () => {
    expect(stableDeepEqual(NaN, NaN)).toBe(true)
    expect(stableDeepEqual({ x: NaN }, { x: NaN })).toBe(true)
    expect(stableDeepEqual(NaN, 0)).toBe(false)
  })

  it('an object and an array of the same length are not equal', () => {
    expect(stableDeepEqual({ 0: 'a', 1: 'b' }, ['a', 'b'])).toBe(false)
  })
})
