/**
 * Integration spec for the ModerationAuditLog repository introduced in
 * migration 20260420010000_add_moderation_audit_log (TEC-2926).
 *
 * Requires a live PostgreSQL test database with the migration applied.
 * Runs under `pnpm --filter api test:integration`.
 */
import { PrismaClient } from '@prisma/client';
import { afterAll, beforeAll, describe, expect, it } from 'vitest';
import { PrismaModerationAuditLogRepository } from '../repositories/prisma-moderation-audit-log.repository';

const prisma = new PrismaClient();
// The repository only depends on prisma.moderationAuditLog — cast is safe here.
const repo = new PrismaModerationAuditLogRepository(prisma as any);

const MODERATOR_A = '00000000-0000-4000-8000-00000000a001';
const MODERATOR_B = '00000000-0000-4000-8000-00000000a002';
const LISTING_A = '00000000-0000-4000-8000-00000000b001';
const LISTING_B = '00000000-0000-4000-8000-00000000b002';

describe('ModerationAuditLog repository (TEC-2926)', () => {
  beforeAll(async () => {
    await prisma.moderationAuditLog.deleteMany({
      where: { moderatorId: { in: [MODERATOR_A, MODERATOR_B] } },
    });
  });

  afterAll(async () => {
    await prisma.moderationAuditLog.deleteMany({
      where: { moderatorId: { in: [MODERATOR_A, MODERATOR_B] } },
    });
    await prisma.$disconnect();
  });

  it('persists a row with the expected columns', async () => {
    const entry = await repo.create({
      targetType: 'listing',
      targetId: LISTING_A,
      action: 'approve',
      moderatorId: MODERATOR_A,
      reason: 'clean',
      metadata: { score: 0.98 },
    });

    expect(entry.id).toBeTruthy();
    expect(entry.targetType).toBe('listing');
    expect(entry.targetId).toBe(LISTING_A);
    expect(entry.action).toBe('approve');
    expect(entry.moderatorId).toBe(MODERATOR_A);
    expect(entry.reason).toBe('clean');
    expect(entry.metadata).toEqual({ score: 0.98 });
    expect(entry.createdAt).toBeInstanceOf(Date);
  });

  it('filters by targetType + targetId', async () => {
    await repo.create({
      targetType: 'listing',
      targetId: LISTING_B,
      action: 'reject',
      moderatorId: MODERATOR_B,
      reason: 'spam',
    });
    await repo.create({
      targetType: 'property',
      targetId: LISTING_B,
      action: 'flag',
      moderatorId: MODERATOR_B,
    });

    const listingOnly = await repo.findAll({
      page: 1,
      limit: 50,
      targetType: 'listing',
      targetId: LISTING_B,
    });

    expect(listingOnly.total).toBeGreaterThanOrEqual(1);
    for (const row of listingOnly.data) {
      expect(row.targetType).toBe('listing');
      expect(row.targetId).toBe(LISTING_B);
    }
  });

  it('filters by moderatorId and by action', async () => {
    const byModerator = await repo.findAll({
      page: 1,
      limit: 50,
      moderatorId: MODERATOR_A,
    });
    expect(byModerator.total).toBeGreaterThanOrEqual(1);
    for (const row of byModerator.data) {
      expect(row.moderatorId).toBe(MODERATOR_A);
    }

    const rejects = await repo.findAll({
      page: 1,
      limit: 50,
      moderatorId: MODERATOR_B,
      action: 'reject',
    });
    for (const row of rejects.data) {
      expect(row.action).toBe('reject');
      expect(row.moderatorId).toBe(MODERATOR_B);
    }
  });

  it('orders newest first and paginates', async () => {
    const page1 = await repo.findAll({
      page: 1,
      limit: 1,
      moderatorId: MODERATOR_B,
    });
    expect(page1.data.length).toBe(1);
    expect(page1.limit).toBe(1);
    expect(page1.page).toBe(1);
    expect(page1.totalPages).toBeGreaterThanOrEqual(1);
  });
});
