import { eq } from 'drizzle-orm'
import { beforeEach, describe, expect, it } from 'vitest'
import type { Querier } from '@platform-modules/db'
import { createPgliteClient } from '../../db/src/postgres/pglite.js'
import { ContentAuthzError, type Actor } from './authz.js'
import { contentEntries, contentSchema, type ContentSchema } from './schema.js'
import { put as putRaw } from './store.js'
import { setupTaxonomyDb } from './taxonomy.test-helpers.js'
import { TermNotFoundError, assignTerms, createTerm } from './taxonomy.js'

function sanitize(raw: string): string {
  return raw
}

const author: Actor = { id: 'author-1' }
const editor: Actor = { id: 'editor-1', canEditAny: true, canPublish: true, canManageTaxonomy: true }
const stranger: Actor = { id: 'stranger' }

function put(d: Querier<ContentSchema>, raw: Parameters<typeof putRaw>[1], actor: Actor = editor) {
  return putRaw(d, raw, actor, sanitize)
}

describe('assignTerms / termsForEntry', () => {
  let d: Querier<ContentSchema>
  beforeEach(async () => {
    d = await setupTaxonomyDb(createPgliteClient({ schema: contentSchema }))
  })

  it('replace-set: re-assign drops old terms', async () => {
    const t1 = await createTerm(d, { taxonomy: 'tag', slug: 'a', name: 'A' }, editor)
    const t2 = await createTerm(d, { taxonomy: 'tag', slug: 'b', name: 'B' }, editor)
    const entry = await put(d, { slug: 'e1', type: 'post', title: 'E', body: '', termIds: [t1.id] })
    expect(entry.terms.map((t) => t.id)).toEqual([t1.id])

    const assigned = await assignTerms(d, entry.id, [t2.id], editor)
    expect(assigned.map((t) => t.id)).toEqual([t2.id])
  })

  it('unknown term id throws TermNotFoundError and leaves entry unchanged', async () => {
    const entry = await put(d, { slug: 'e2', type: 'post', title: 'E', body: '' })
    const bogus = '00000000-0000-4000-8000-000000000099'

    await expect(assignTerms(d, entry.id, [bogus], editor)).rejects.toBeInstanceOf(TermNotFoundError)

    const [row] = await d.select().from(contentEntries).where(eq(contentEntries.id, entry.id))
    expect(row?.title).toBe('E')
  })

  it('denies non-modify actor', async () => {
    const entry = await put(d, { slug: 'e3', type: 'post', title: 'E', body: '' }, author)
    const t = await createTerm(d, { taxonomy: 'tag', slug: 'x', name: 'X' }, editor)
    await expect(assignTerms(d, entry.id, [t.id], stranger)).rejects.toBeInstanceOf(ContentAuthzError)
  })
})
