import { describe, it, expect, beforeAll, afterAll, beforeEach } from 'vitest';
import { PrismaClient } from '@prisma/client';
import { resetDb } from '../test-utils/reset-db';
import { type MessagePrincipal } from '../messaging/message.service';
import { ActorResolver } from '../identity/actor.resolver';
import { CalendarAdapter } from './calendar-adapter';
import type { PrismaService } from '../prisma/prisma.service';

const url = process.env.DATABASE_URL ?? 'postgresql://iios:iios@localhost:5434/iios?schema=public';
const prisma = new PrismaClient({ datasources: { db: { url } } });
const asService = prisma as unknown as PrismaService;
const actors = new ActorResolver(asService);
const adapter = () => new CalendarAdapter(asService, actors);

const alice: MessagePrincipal = { userId: 'alice', orgId: 'org_demo', appId: 'portal-demo', displayName: 'Alice' };

beforeAll(async () => { await prisma.$connect(); });
afterAll(async () => { await prisma.$disconnect(); });
beforeEach(async () => { await resetDb(prisma); });

describe('CalendarAdapter (P8 — simulated, no network)', () => {
  it('connect → provider account + sync cursor', async () => {
    const acct = await adapter().connectProvider(alice);
    expect(acct.providerType).toBe('SIMULATED');
    const cursor = await prisma.iiosCalendarSyncCursor.findUniqueOrThrow({ where: { providerAccountId: acct.id } });
    expect(cursor.status).toBe('IDLE');
  });

  it('syncOnce twice advances the cursor without duplicating events (idempotent)', async () => {
    const acct = await adapter().connectProvider(alice);
    const r1 = await adapter().syncOnce(acct.id);
    const r2 = await adapter().syncOnce(acct.id);
    expect(Number(r2.cursor)).toBeGreaterThan(Number(r1.cursor));
    expect(await prisma.iiosCalendarEvent.count({ where: { providerAccountId: acct.id } })).toBe(2);
  });

  it('availability reflects a busy synced calendar event', async () => {
    const acct = await adapter().connectProvider(alice);
    await adapter().syncOnce(acct.id);
    const busy = await adapter().availability(alice, { startAt: '2026-07-02T09:15:00.000Z', endAt: '2026-07-02T09:45:00.000Z' });
    expect(busy.free).toBe(false);
    const free = await adapter().availability(alice, { startAt: '2026-07-02T18:00:00.000Z', endAt: '2026-07-02T18:30:00.000Z' });
    expect(free.free).toBe(true);
  });
});
