// favela label consumption (moderation) — LabelStore index by subject + LWW/negation + labelTreatment.
// Run: `bare test/labels.test.mjs`
import '../lib/bare-globals.js'
import { storeDir } from './_store-dir.mjs'
import Corestore from 'corestore'
import { LabelStore, labelTreatment, postModeration } from '../lib/labels.js'
const assert = (cond, msg) => { if (!cond) throw new Error('FAIL: ' + msg); console.log(' ok -', msg) }
const dir = storeDir('labels-test')
const store = new Corestore(dir)
const ls = await new LabelStore(store).ready()
const URI = 'at://did:plc:alice/app.bsky.feed.post/1'
const URI2 = 'at://did:plc:alice/app.bsky.feed.post/10' // prefix neighbour of URI
const SRC = 'did:plc:labeler'
await ls.addLabel({ src: SRC, uri: URI, val: 'spam', cts: '2026-07-01T00:00:00.000Z' })
await ls.addLabel({ src: SRC, uri: URI, val: '!warn', cts: '2026-07-01T00:00:00.000Z' })
await ls.addLabel({ src: SRC, uri: URI2, val: 'nsfw', cts: '2026-07-01T00:00:00.000Z' })
let on1 = await ls.getLabels(URI)
assert(on1.length === 2, 'two active labels on the post')
assert(on1.some(l => l.val === 'spam') && on1.some(l => l.val === '!warn'), 'labels are spam + !warn')
assert((await ls.getLabels(URI2)).length === 1, 'prefix-neighbour URI (…/10) is a SEPARATE subject (no prefix bleed)')
// LWW: an older cts does not override
assert(await ls.addLabel({ src: SRC, uri: URI, val: 'spam', cts: '2026-06-01T00:00:00.000Z' }) === false, 'older cts is ignored (LWW)')
// negation retracts the val (newer cts)
assert(await ls.addLabel({ src: SRC, uri: URI, val: 'spam', cts: '2026-07-05T00:00:00.000Z', neg: true }) === true, 'newer negation applied')
on1 = await ls.getLabels(URI)
assert(on1.length === 1 && on1[0].val === '!warn', 'negated label (spam) no longer active; !warn remains')
// re-apply after negation (even newer cts)
await ls.addLabel({ src: SRC, uri: URI, val: 'spam', cts: '2026-07-09T00:00:00.000Z' })
assert((await ls.getLabels(URI)).some(l => l.val === 'spam'), 're-applied (non-neg, newer) label is active again')
// --- labelTreatment ---
assert(labelTreatment([{ val: '!hide' }]) === 'hide', 'system !hide -> hide (always honored)')
assert(labelTreatment([{ val: '!warn' }]) === 'warn', 'system !warn -> warn')
assert(labelTreatment([{ val: 'custom' }]) === 'ignore', 'unknown custom val -> ignore (no policy)')
assert(labelTreatment([{ val: 'nsfw' }], { nsfw: 'warn' }) === 'warn', 'policy maps a custom val -> warn')
assert(labelTreatment([{ val: 'nsfw' }, { val: '!hide' }], { nsfw: 'warn' }) === 'hide', 'strongest treatment wins (hide > warn)')
assert(labelTreatment([]) === 'ignore', 'no labels -> ignore')
// --- postModeration (labeler labels + modlist mute, combined) ---
let m = postModeration([{ val: '!warn' }], false)
assert(m.treatment === 'warn' && m.muted === false && m.labels[0] === '!warn', 'labels only -> treatment from labels, not muted')
m = postModeration([], true)
assert(m.treatment === 'ignore' && m.muted === true && m.labels.length === 0, 'muted author with no labels -> muted:true, treatment ignore')
m = postModeration([{ val: 'nsfw' }], true, { nsfw: 'warn' })
assert(m.treatment === 'warn' && m.muted === true, 'both layers reported independently (warn label + muted)')
m = postModeration([], false)
assert(m.treatment === 'ignore' && m.muted === false, 'clean post -> nothing applied')
console.log('\nLABELS(consume) OK: index + LWW/negation + prefix-safe + labelTreatment + postModeration')
await ls.close()
try { await store.close() } catch {}