import 'reflect-metadata';
import { afterAll, beforeAll, describe, expect, it, vi } from 'vitest';
import { Global, Module } from '@nestjs/common';
import { Test } from '@nestjs/testing';
import { FastifyAdapter, type NestFastifyApplication } from '@nestjs/platform-fastify';
import { AUTH } from '../auth/auth.tokens.js';
import { AuthGuard } from '../auth/auth.guard.js';
import { InteractionCoordinationController } from './interaction-coordination.controller.js';
import { InteractionCoordinationService } from './interaction-coordination.service.js';

@Global()
@Module({
  providers: [
    {
      provide: AUTH,
      useValue: {
        api: {
          getSession: vi.fn(async ({ headers }: { headers: Headers }) =>
            headers.get('cookie') === 'session=trusted'
              ? { user: { id: 'operator-1', tenantId: 'tenant-1' }, session: { id: 'session-1' } }
              : null,
          ),
        },
      },
    },
    AuthGuard,
  ],
  exports: [AUTH, AuthGuard],
})
class AuthenticatedRequestModule {}

describe('InteractionCoordinationController route aliases', (): void => {
  let app: NestFastifyApplication | undefined;
  const coordination = {
    handoff: vi.fn(async () => ({ handoffId: 'handoff-1' })),
    observe: vi.fn(async () => ({ status: 'running' })),
    result: vi.fn(async () => ({ status: 'completed' })),
  };

  beforeAll(async (): Promise<void> => {
    const moduleRef = await Test.createTestingModule({
      imports: [AuthenticatedRequestModule],
      controllers: [InteractionCoordinationController],
      providers: [{ provide: InteractionCoordinationService, useValue: coordination }],
    }).compile();
    app = moduleRef.createNestApplication<NestFastifyApplication>(new FastifyAdapter());
    await app.init();
    await app.getHttpAdapter().getInstance().ready();
  });
  afterAll(async (): Promise<void> => app?.close());

  it('routes handoff, observe, and result through the same AuthGuard-protected service for both prefixes', async (): Promise<void> => {
    if (!app) throw new Error('test app was not initialized');
    for (const prefix of ['/api/coord/interaction', '/api/coord/mos']) {
      const headers = { cookie: 'session=trusted', 'x-correlation-id': `corr-${prefix}` };
      expect(
        (
          await app.inject({
            method: 'POST',
            url: `${prefix}/handoff`,
            headers,
            payload: { idempotencyKey: `key-${prefix}`, summary: 'handoff' },
          })
        ).statusCode,
      ).toBe(201);
      expect(
        (await app.inject({ method: 'GET', url: `${prefix}/handoff-1/observe`, headers }))
          .statusCode,
      ).toBe(200);
      expect(
        (await app.inject({ method: 'GET', url: `${prefix}/handoff-1/result`, headers }))
          .statusCode,
      ).toBe(200);
    }
    expect(coordination.handoff).toHaveBeenCalledTimes(2);
    expect(coordination.observe).toHaveBeenCalledTimes(2);
    expect(coordination.result).toHaveBeenCalledTimes(2);
    expect(
      (
        await app.inject({
          method: 'POST',
          url: '/api/coord/interaction/handoff',
          payload: { idempotencyKey: 'denied', summary: 'x' },
        })
      ).statusCode,
    ).toBe(401);
  });
});
