import { eq, sql } from 'drizzle-orm'
import { afterAll, beforeAll, describe, expect, it } from 'vitest'
import type { Querier } from '@platform-modules/db'
import { type Actor } from './authz.js'
import { startPg } from './pg-harness.js'
import { setupTaxonomyDb } from './taxonomy.test-helpers.js'
import { contentEntries, type ContentSchema } from './schema.js'
import { promoteScheduled, put as putRaw } from './store.js'

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

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

const CREATE_TABLE = sql`
  CREATE TABLE content_entries (
    id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
    slug text NOT NULL,
    type text NOT NULL,
    title text NOT NULL,
    body text NOT NULL DEFAULT '',
    status text NOT NULL DEFAULT 'draft',
    visibility text NOT NULL DEFAULT 'public',
    published_at timestamptz(3),
    author text NOT NULL,
    created_at timestamptz(3) NOT NULL DEFAULT NOW(),
    updated_at timestamptz(3) NOT NULL DEFAULT NOW()
  )
`

const CREATE_INDEX = sql`
  CREATE UNIQUE INDEX content_entries_type_slug_uq ON content_entries (type, slug)
`

describe('promoteScheduled concurrency (real PG)', () => {
  let db: Querier<ContentSchema>
  let dbB: Querier<ContentSchema>
  let stop: () => Promise<void>

  beforeAll(async () => {
    const pg = await startPg()
    db = pg.db
    dbB = pg.dbB
    stop = pg.stop
    await setupTaxonomyDb(db)
  }, 45_000)

  afterAll(async () => {
    await stop?.()
  }, 15_000)

  it('two concurrent promoteScheduled calls publish a due scheduled row exactly once', async () => {
    const now = new Date('2026-06-19T12:00:00.000Z')
    const past = new Date('2026-06-19T11:00:00.000Z')

    const entry = await putRaw(
      db,
      { slug: 'race', type: 'post', title: 'Race', body: '' },
      editor,
      sanitize,
    )
    await db.execute(
      sql`UPDATE content_entries SET status = 'scheduled', published_at = ${past} WHERE id = ${entry.id}`,
    )

    const [refsA, refsB] = await Promise.all([promoteScheduled(db, now), promoteScheduled(dbB, now)])

    const promotedIds = [...refsA, ...refsB].map((r) => r.id)
    expect(promotedIds.filter((id) => id === entry.id)).toHaveLength(1)

    const [row] = await db.select().from(contentEntries).where(eq(contentEntries.id, entry.id))
    expect(row!.status).toBe('published')

    const published = await db.select().from(contentEntries).where(eq(contentEntries.status, 'published'))
    expect(published).toHaveLength(1)
  }, 45_000)
})
