import { describe, it, expect, beforeAll, afterAll, beforeEach } from 'vitest';
import type { PrismaClient } from '@prisma/client';
import { setupTestDb, cleanupTestDb, clearAllTables } from './helpers.js';

describe('ResourceRevision schema', () => {
  let prisma: PrismaClient;

  beforeAll(async () => {
    prisma = await setupTestDb();
  }, 30_000);

  afterAll(async () => {
    await cleanupTestDb();
  });

  beforeEach(async () => {
    await clearAllTables(prisma);
  });

  it('creates a revision with required fields and defaults', async () => {
    const rev = await prisma.resourceRevision.create({
      data: {
        resourceType: 'prompt',
        resourceId: 'fake-prompt-id',
        contentHash: 'sha256:abc',
        body: { content: 'hello' },
      },
    });
    expect(rev.id).toBeDefined();
    expect(rev.semver).toBe('0.1.0');
    expect(rev.note).toBe('');
    expect(rev.authorUserId).toBeNull();
    expect(rev.authorSessionId).toBeNull();
    expect(rev.body).toEqual({ content: 'hello' });
    expect(rev.createdAt).toBeInstanceOf(Date);
  });

  it('survives resource deletion (soft FK)', async () => {
    // No actual prompt exists with this id — the soft FK design lets
    // revisions outlive their resources.
    const rev = await prisma.resourceRevision.create({
      data: {
        resourceType: 'skill',
        resourceId: 'never-existed',
        contentHash: 'sha256:def',
        body: { content: 'ghost' },
      },
    });
    expect(rev.resourceId).toBe('never-existed');
  });

  it('orders revisions latest-first within a resource', async () => {
    const resourceId = 'r1';
    const a = await prisma.resourceRevision.create({
      data: {
        resourceType: 'prompt', resourceId,
        semver: '0.1.0', contentHash: 'h1', body: {},
      },
    });
    await new Promise((r) => setTimeout(r, 10));
    const b = await prisma.resourceRevision.create({
      data: {
        resourceType: 'prompt', resourceId,
        semver: '0.1.1', contentHash: 'h2', body: {},
      },
    });
    await new Promise((r) => setTimeout(r, 10));
    const c = await prisma.resourceRevision.create({
      data: {
        resourceType: 'prompt', resourceId,
        semver: '0.2.0', contentHash: 'h3', body: {},
      },
    });

    const rows = await prisma.resourceRevision.findMany({
      where: { resourceType: 'prompt', resourceId },
      orderBy: { createdAt: 'desc' },
    });
    expect(rows.map((r) => r.id)).toEqual([c.id, b.id, a.id]);
  });

  it('allows multiple revisions with the same contentHash (rollback)', async () => {
    const resourceId = 'r2';
    await prisma.resourceRevision.create({
      data: {
        resourceType: 'prompt', resourceId,
        semver: '0.1.0', contentHash: 'identical', body: {},
      },
    });
    const second = await prisma.resourceRevision.create({
      data: {
        resourceType: 'prompt', resourceId,
        semver: '0.2.0', contentHash: 'identical', body: {},
      },
    });
    expect(second.id).toBeDefined();
    const rows = await prisma.resourceRevision.findMany({
      where: { contentHash: 'identical' },
    });
    expect(rows.length).toBe(2);
  });

  it('discriminates between prompt and skill revisions', async () => {
    await prisma.resourceRevision.create({
      data: { resourceType: 'prompt', resourceId: 'x', contentHash: 'a', body: {} },
    });
    await prisma.resourceRevision.create({
      data: { resourceType: 'skill', resourceId: 'x', contentHash: 'a', body: {} },
    });
    const prompts = await prisma.resourceRevision.findMany({
      where: { resourceType: 'prompt', resourceId: 'x' },
    });
    const skills = await prisma.resourceRevision.findMany({
      where: { resourceType: 'skill', resourceId: 'x' },
    });
    expect(prompts.length).toBe(1);
    expect(skills.length).toBe(1);
  });
});
