import { test } from 'node:test'
import assert from 'node:assert/strict'
import { describe, categoryOf, kindLabel, CATEGORIES } from '../src/lib/shardEvents.js'

// Unit-test the shared shard-event formatter — the single place that decides how
// each event kind reads and which filter category it belongs to. These strings
// are user-facing on the public Shard page, the Activity feed, and the admin
// live feed, so a regression here is visible everywhere at once.

// ── describe(): works on both stored (.payload) and live (top-level) frames ──
test('describe reads fields from .payload when present, else the top level', () => {
  const stored = { kind: 'quest.complete', payload: { who: { name: 'Ada' }, quest: 'The Cavern' } }
  const live = { kind: 'quest.complete', who: { name: 'Ada' }, quest: 'The Cavern' }
  assert.equal(describe(stored), 'Ada completed “The Cavern”')
  assert.equal(describe(live), 'Ada completed “The Cavern”')
})

test('describe resolves an actor from name → acct → "Someone"', () => {
  assert.equal(describe({ kind: 'mob.login', who: { name: 'Bob' } }), 'Bob entered the world')
  assert.equal(describe({ kind: 'mob.login', who: { acct: 'acct7' } }), 'acct7 entered the world')
  assert.equal(describe({ kind: 'mob.login', who: null }), 'Someone entered the world')
  assert.equal(describe({ kind: 'mob.login', who: 'RawString' }), 'RawString entered the world')
})

test('describe pluralizes a vendor sale only when amount > 1 and formats the price', () => {
  assert.equal(describe({ kind: 'vendor.sale', itemType: 'Katana', amount: 1, price: 1200 }), 'Katana sold for 1,200gp')
  assert.equal(describe({ kind: 'vendor.sale', itemType: 'Arrow', amount: 40, price: 80 }), 'Arrow ×40 sold for 80gp')
})

test('describe includes the killer only when present (optional clause)', () => {
  assert.equal(describe({ kind: 'player.death', who: { name: 'Ada' } }), 'Ada was slain')
  assert.equal(
    describe({ kind: 'player.death', who: { name: 'Ada' }, killer: { name: 'Orc' } }),
    'Ada was slain by Orc',
  )
})

test('describe champ.update branches on status and boss state', () => {
  assert.equal(describe({ kind: 'champ.update', name: 'Rikktor', status: 'active', bossUp: true }), 'Rikktor: boss is up')
  assert.equal(
    describe({ kind: 'champ.update', name: 'Rikktor', status: 'active', level: 3 }),
    'Rikktor is active — level 3',
  )
  assert.equal(describe({ kind: 'champ.update', name: 'Rikktor', status: 'cooldown' }), 'Rikktor is on cooldown')
})

test('describe falls back to the raw kind for an unknown event', () => {
  assert.equal(describe({ kind: 'some.future.kind' }), 'some.future.kind')
})

// ── categoryOf(): membership + catch-all ────────────────────────────────
test('categoryOf groups kinds per the CATEGORIES table, and unknowns are "other"', () => {
  assert.equal(categoryOf('player.death'), 'pvp')
  assert.equal(categoryOf('skill.gain'), 'progress')
  assert.equal(categoryOf('house.decay'), 'world')
  assert.equal(categoryOf('vendor.sale'), 'other') // deliberately not a public category
  assert.equal(categoryOf('totally.unknown'), 'other')
})

test('every kind listed in CATEGORIES maps back to that category (table stays consistent)', () => {
  for (const cat of CATEGORIES) {
    if (!cat.kinds) continue
    for (const kind of cat.kinds) {
      assert.equal(categoryOf(kind), cat.id, `${kind} should be in ${cat.id}`)
    }
  }
})

// ── kindLabel(): badge text ─────────────────────────────────────────────
test('kindLabel turns dots/underscores into spaces and tolerates empty input', () => {
  assert.equal(kindLabel('player.death'), 'player death')
  assert.equal(kindLabel('account.login.attempt'), 'account login attempt')
  assert.equal(kindLabel(null), '')
})
