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

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

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

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

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

  async function createUser() {
    return prisma.user.create({
      data: {
        email: `test-${Date.now()}-${Math.random()}@example.com`,
        name: 'Test',
        passwordHash: '!locked',
        role: 'USER',
      },
    });
  }

  async function createProject(name = `project-${Date.now()}-${Math.random()}`) {
    const user = await createUser();
    return prisma.project.create({ data: { name, ownerId: user.id } });
  }

  it('creates a pending prompt proposal with defaults', async () => {
    const project = await createProject();
    const proposal = await prisma.resourceProposal.create({
      data: {
        resourceType: 'prompt',
        name: 'my-proposal',
        body: { content: 'hello', priority: 5 },
        projectId: project.id,
      },
    });
    expect(proposal.id).toBeDefined();
    expect(proposal.status).toBe('pending');
    expect(proposal.reviewerNote).toBe('');
    expect(proposal.approvedRevisionId).toBeNull();
    expect(proposal.version).toBe(1);
    expect(proposal.body).toEqual({ content: 'hello', priority: 5 });
  });

  it('creates a pending skill proposal', async () => {
    const project = await createProject();
    const proposal = await prisma.resourceProposal.create({
      data: {
        resourceType: 'skill',
        name: 'my-skill-proposal',
        body: { content: 'SKILL.md body', metadata: { postInstall: 'hooks/x.sh' } },
        projectId: project.id,
      },
    });
    expect(proposal.resourceType).toBe('skill');
  });

  it('enforces unique (resourceType, name, projectId)', async () => {
    const project = await createProject();
    await prisma.resourceProposal.create({
      data: {
        resourceType: 'prompt',
        name: 'dup',
        body: { content: 'a' },
        projectId: project.id,
      },
    });
    await expect(
      prisma.resourceProposal.create({
        data: {
          resourceType: 'prompt',
          name: 'dup',
          body: { content: 'b' },
          projectId: project.id,
        },
      }),
    ).rejects.toThrow();
  });

  it('allows same name across different resource types in same project', async () => {
    const project = await createProject();
    await prisma.resourceProposal.create({
      data: {
        resourceType: 'prompt',
        name: 'shared',
        body: { content: 'a' },
        projectId: project.id,
      },
    });
    const second = await prisma.resourceProposal.create({
      data: {
        resourceType: 'skill',
        name: 'shared',
        body: { content: 'b' },
        projectId: project.id,
      },
    });
    expect(second.id).toBeDefined();
  });

  it('allows status lifecycle: pending → approved', async () => {
    const project = await createProject();
    const proposal = await prisma.resourceProposal.create({
      data: {
        resourceType: 'prompt',
        name: 'flow',
        body: { content: 'hi' },
        projectId: project.id,
      },
    });
    const approved = await prisma.resourceProposal.update({
      where: { id: proposal.id },
      data: {
        status: 'approved',
        reviewerNote: 'looks good',
        approvedRevisionId: 'rev-fake-123',
      },
    });
    expect(approved.status).toBe('approved');
    expect(approved.reviewerNote).toBe('looks good');
    expect(approved.approvedRevisionId).toBe('rev-fake-123');
  });

  it('cascades on project delete', async () => {
    const project = await createProject();
    const proposal = await prisma.resourceProposal.create({
      data: {
        resourceType: 'prompt',
        name: 'will-cascade',
        body: { content: 'hi' },
        projectId: project.id,
      },
    });
    await prisma.project.delete({ where: { id: project.id } });
    const found = await prisma.resourceProposal.findUnique({ where: { id: proposal.id } });
    expect(found).toBeNull();
  });
});
