/**
 * Batch Credential Issuance Tests
 */

import { describe, it, expect, vi, beforeEach } from 'vitest';
import { registerBatchIssuance, BatchIssuanceRequest } from './batch-issuance';
import { KMSClient } from '@the-order/crypto';
import { createVerifiableCredential, logCredentialAction } from '@the-order/database';
import { getEnv, authenticateJWT, requireRole } from '@the-order/shared';
import type { FastifyInstance, FastifyRequest, FastifyReply } from 'fastify';

vi.mock('@the-order/crypto');
vi.mock('@the-order/database');
vi.mock('@the-order/shared');

describe('Batch Credential Issuance', () => {
  let server: FastifyInstance;
  let kmsClient: KMSClient;

  beforeEach(() => {
    server = {
      post: vi.fn((route, options, handler) => {
        // Store handler for testing
        (server as any)._handler = handler;
      }),
      log: {
        info: vi.fn(),
        error: vi.fn(),
        warn: vi.fn(),
      },
    } as any;

    kmsClient = {
      sign: vi.fn().mockResolvedValue(Buffer.from('test-signature')),
    } as any;

    vi.mocked(getEnv).mockReturnValue({
      VC_ISSUER_DID: 'did:web:example.com',
      VC_ISSUER_DOMAIN: undefined,
    } as any);

    vi.mocked(createVerifiableCredential).mockResolvedValue({
      id: 'test-credential-id',
      credential_id: 'test-credential-id',
      issuer_did: 'did:web:example.com',
      subject_did: 'did:web:subject.com',
      credential_type: ['VerifiableCredential'],
      credential_subject: {},
      issuance_date: new Date(),
      revoked: false,
      created_at: new Date(),
      updated_at: new Date(),
    } as any);

    vi.mocked(logCredentialAction).mockResolvedValue({
      id: 'audit-id',
      credential_id: 'test-credential-id',
      action: 'issued',
      performed_at: new Date(),
    } as any);

    vi.clearAllMocks();
  });

  describe('registerBatchIssuance', () => {
    it('should register batch issuance endpoint', async () => {
      await registerBatchIssuance(server, kmsClient);

      expect(server.post).toHaveBeenCalledWith(
        '/vc/issue/batch',
        expect.objectContaining({
          preHandler: expect.any(Array),
          schema: expect.objectContaining({
            description: 'Batch issue verifiable credentials',
          }),
        }),
        expect.any(Function)
      );
    });

    it('should process batch issuance request', async () => {
      await registerBatchIssuance(server, kmsClient);

      const handler = (server as any)._handler;
      const request = {
        body: {
          credentials: [
            {
              subject: 'did:web:subject1.com',
              credentialSubject: { name: 'Test User 1' },
            },
            {
              subject: 'did:web:subject2.com',
              credentialSubject: { name: 'Test User 2' },
            },
          ],
        } as BatchIssuanceRequest,
        ip: '127.0.0.1',
        headers: { 'user-agent': 'test-agent' },
        user: { id: 'admin-user-id' },
      } as any;

      const reply = {
        code: vi.fn().mockReturnThis(),
        send: vi.fn().mockReturnThis(),
      } as any;

      await handler(request, reply);

      expect(createVerifiableCredential).toHaveBeenCalledTimes(2);
      expect(logCredentialAction).toHaveBeenCalledTimes(2);
      expect(reply.send).toHaveBeenCalledWith(
        expect.objectContaining({
          jobId: expect.any(String),
          total: 2,
          accepted: 2,
          results: expect.arrayContaining([
            expect.objectContaining({
              index: 0,
              credentialId: expect.any(String),
            }),
            expect.objectContaining({
              index: 1,
              credentialId: expect.any(String),
            }),
          ]),
        })
      );
    });

    it('should handle errors in batch issuance', async () => {
      await registerBatchIssuance(server, kmsClient);

      vi.mocked(createVerifiableCredential).mockRejectedValueOnce(new Error('Database error'));

      const handler = (server as any)._handler;
      const request = {
        body: {
          credentials: [
            {
              subject: 'did:web:subject1.com',
              credentialSubject: { name: 'Test User 1' },
            },
          ],
        } as BatchIssuanceRequest,
        ip: '127.0.0.1',
        headers: { 'user-agent': 'test-agent' },
        user: { id: 'admin-user-id' },
      } as any;

      const reply = {
        code: vi.fn().mockReturnThis(),
        send: vi.fn().mockReturnThis(),
      } as any;

      await handler(request, reply);

      expect(reply.send).toHaveBeenCalledWith(
        expect.objectContaining({
          jobId: expect.any(String),
          total: 1,
          accepted: 0,
          results: expect.arrayContaining([
            expect.objectContaining({
              index: 0,
              error: 'Database error',
            }),
          ]),
        })
      );
    });

    it('should return error if issuer DID not configured', async () => {
      vi.mocked(getEnv).mockReturnValue({
        VC_ISSUER_DID: undefined,
        VC_ISSUER_DOMAIN: undefined,
      } as any);

      await registerBatchIssuance(server, kmsClient);

      const handler = (server as any)._handler;
      const request = {
        body: {
          credentials: [
            {
              subject: 'did:web:subject1.com',
              credentialSubject: { name: 'Test User 1' },
            },
          ],
        } as BatchIssuanceRequest,
      } as any;

      const reply = {
        code: vi.fn().mockReturnThis(),
        send: vi.fn().mockReturnThis(),
      } as any;

      await handler(request, reply);

      expect(reply.code).toHaveBeenCalledWith(500);
      expect(reply.send).toHaveBeenCalledWith(
        expect.objectContaining({
          error: expect.objectContaining({
            code: 'CONFIGURATION_ERROR',
          }),
        })
      );
    });
  });
});

