import { PGlite } from '@electric-sql/pglite'
import { drizzle } from 'drizzle-orm/pglite'
import type { TransactionalDatabase } from '@platform-modules/db'
import {
  addAttachment,
  computeDue,
  helpdeskSchema,
  isBreached,
  isValidTransition,
  listAttachments,
  listMessages,
  postMessage,
  type HelpdeskSchema,
  type SupportCase,
} from '@platform-modules/helpdesk'
import { describe, expect, it } from 'vitest'

const ticketAdjacency = {
  open: ['pending', 'closed'],
  pending: ['open', 'closed'],
  closed: [],
} as const

async function createHarnessDb(): Promise<TransactionalDatabase<HelpdeskSchema>> {
  const client = new PGlite()
  const db = drizzle(client, { schema: helpdeskSchema }) as unknown as TransactionalDatabase<HelpdeskSchema>

  await client.exec(`
    CREATE TABLE support_messages (
      id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
      parent_type text NOT NULL,
      parent_id text NOT NULL,
      author_type text NOT NULL,
      body text NOT NULL,
      visibility text,
      created_at timestamptz NOT NULL DEFAULT NOW()
    );

    CREATE TABLE support_state_transitions (
      id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
      parent_type text NOT NULL,
      parent_id text NOT NULL,
      from_status text NOT NULL,
      to_status text NOT NULL,
      actor_id text NOT NULL,
      reason text,
      at timestamptz NOT NULL DEFAULT NOW()
    );

    CREATE TABLE support_attachments (
      id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
      parent_type text NOT NULL,
      parent_id text NOT NULL,
      object_key text NOT NULL,
      file_name text,
      mime_type text,
      created_at timestamptz NOT NULL DEFAULT NOW()
    );

    CREATE TABLE sla_policies (
      scope_key text PRIMARY KEY,
      target text NOT NULL,
      due_minutes integer NOT NULL
    );
  `)

  return db
}

describe('helpdesk consumer fixture (Gate 3)', () => {
  it('isolates threaded messages by (parentType, parentId) across ticket and case parent types', async () => {
    const db = await createHarnessDb()

    await postMessage(db, { parentType: 'ticket', parentId: 'shared-1' }, {
      authorType: 'customer',
      body: 'ticket thread',
    })
    await postMessage(db, { parentType: 'case', parentId: 'shared-1' }, {
      authorType: 'staff',
      body: 'case thread',
    })

    const ticketMessages = await listMessages(db, { parentType: 'ticket', parentId: 'shared-1' })
    const caseMessages = await listMessages(db, { parentType: 'case', parentId: 'shared-1' })

    expect(ticketMessages).toHaveLength(1)
    expect(caseMessages).toHaveLength(1)
    expect(ticketMessages[0]?.body).toBe('ticket thread')
    expect(caseMessages[0]?.body).toBe('case thread')

    // Regression harness: removing parentType scoping would surface both bodies here.
    expect(ticketMessages.some((row) => row.body === 'case thread')).toBe(false)
  })

  it('accepts a legal transition edge and rejects an illegal one via host adjacency', () => {
    expect(isValidTransition(ticketAdjacency, 'open', 'pending')).toBe(true)
    expect(isValidTransition(ticketAdjacency, 'open', 'resolved')).toBe(false)
  })

  it('flips the host-owned slaBreached flag once the due time passes', () => {
    const openedAt = new Date('2026-06-15T10:00:00.000Z')
    const dueAt = computeDue(
      { scopeKey: 'ticket:default', target: 'first_response', dueMinutes: 60 },
      openedAt,
    )

    const beforeDue: SupportCase = {
      id: 'ticket-1',
      status: 'open',
      slaBreached: isBreached(dueAt, new Date('2026-06-15T10:30:00.000Z')),
    }
    const afterDue: SupportCase = {
      id: 'ticket-1',
      status: 'open',
      slaBreached: isBreached(dueAt, new Date('2026-06-15T11:30:00.000Z')),
    }

    expect(beforeDue.slaBreached).toBe(false)
    expect(afterDue.slaBreached).toBe(true)
  })

  it('does not leak a case attachment to a ticket with the same parentId', async () => {
    const db = await createHarnessDb()

    await addAttachment(db, { parentType: 'case', parentId: 'shared-2' }, {
      objectKey: 'r2://case/evidence.pdf',
      fileName: 'evidence.pdf',
    })

    const ticketAttachments = await listAttachments(db, { parentType: 'ticket', parentId: 'shared-2' })
    expect(ticketAttachments).toEqual([])
  })
})
