/**
 * MPC Party Controller Integration Tests
 *
 * Note: Full controller integration tests require the complete app setup.
 * These are simplified tests for core functionality.
 */

import { Test, TestingModule } from '@nestjs/testing';
import { MPCPartyController } from '../../src/api/controllers/mpc-party.controller';
import { MPCPartyApplicationService } from '../../src/application/services/mpc-party-application.service';
import { PartyShareType } from '../../src/domain/enums';
import { JwtService } from '@nestjs/jwt';
import { ConfigService } from '@nestjs/config';
import { Reflector } from '@nestjs/core';

describe('MPCPartyController (Integration)', () => {
  let controller: MPCPartyController;
  let mockApplicationService: any;

  beforeEach(async () => {
    mockApplicationService = {
      participateInKeygen: jest.fn(),
      participateInSigning: jest.fn(),
      rotateShare: jest.fn(),
      getShareInfo: jest.fn(),
      listShares: jest.fn(),
    };

    const module: TestingModule = await Test.createTestingModule({
      controllers: [MPCPartyController],
      providers: [
        { provide: MPCPartyApplicationService, useValue: mockApplicationService },
        { provide: JwtService, useValue: { verifyAsync: jest.fn() } },
        { provide: ConfigService, useValue: { get: jest.fn() } },
        { provide: Reflector, useValue: { getAllAndOverride: jest.fn().mockReturnValue(true) } },
      ],
    }).compile();

    controller = module.get<MPCPartyController>(MPCPartyController);
  });

  it('should be defined', () => {
    expect(controller).toBeDefined();
  });

  describe('health', () => {
    it('should return health status', () => {
      const result = controller.health();
      expect(result.status).toBe('ok');
      expect(result.service).toBe('mpc-party-service');
      expect(result.timestamp).toBeDefined();
    });
  });

  describe('listShares', () => {
    it('should call application service listShares', async () => {
      const mockResult = {
        items: [],
        total: 0,
        page: 1,
        limit: 10,
        totalPages: 0,
      };

      mockApplicationService.listShares.mockResolvedValue(mockResult);

      const query = {
        partyId: 'user123-server',
        page: 1,
        limit: 10,
      };

      const result = await controller.listShares(query);

      expect(mockApplicationService.listShares).toHaveBeenCalledWith({
        partyId: 'user123-server',
        status: undefined,
        shareType: undefined,
        publicKey: undefined,
        page: 1,
        limit: 10,
      });
      expect(result).toEqual(mockResult);
    });
  });

  describe('getShareInfo', () => {
    it('should call application service getShareInfo', async () => {
      const mockResult = {
        shareId: 'share-123',
        partyId: 'user123-server',
        publicKey: '03' + '0'.repeat(64),
        threshold: '2-of-3',
        status: 'active',
      };

      mockApplicationService.getShareInfo.mockResolvedValue(mockResult);

      const result = await controller.getShareInfo('share-123');

      expect(mockApplicationService.getShareInfo).toHaveBeenCalledWith('share-123');
      expect(result).toEqual(mockResult);
    });
  });

  describe('participateInKeygen', () => {
    it('should return accepted response for async keygen', async () => {
      // Mock the promise that won't resolve during the test
      mockApplicationService.participateInKeygen.mockReturnValue(new Promise(() => {}));

      const dto = {
        sessionId: '550e8400-e29b-41d4-a716-446655440000',
        partyId: 'user123-server',
        joinToken: 'join-token-abc',
        shareType: PartyShareType.WALLET,
        userId: 'user-id-123',
      };

      const result = await controller.participateInKeygen(dto);

      expect(result).toEqual({
        message: 'Keygen participation started',
        sessionId: dto.sessionId,
        partyId: dto.partyId,
      });
    });
  });

  describe('participateInKeygenSync', () => {
    it('should call application service and return result', async () => {
      const mockResult = {
        shareId: 'share-123',
        publicKey: '03' + '0'.repeat(64),
        threshold: '2-of-3',
        sessionId: '550e8400-e29b-41d4-a716-446655440000',
        partyId: 'user123-server',
      };

      mockApplicationService.participateInKeygen.mockResolvedValue(mockResult);

      const dto = {
        sessionId: '550e8400-e29b-41d4-a716-446655440000',
        partyId: 'user123-server',
        joinToken: 'join-token-abc',
        shareType: PartyShareType.WALLET,
        userId: 'user-id-123',
      };

      const result = await controller.participateInKeygenSync(dto);

      expect(mockApplicationService.participateInKeygen).toHaveBeenCalledWith({
        sessionId: dto.sessionId,
        partyId: dto.partyId,
        joinToken: dto.joinToken,
        shareType: dto.shareType,
        userId: dto.userId,
      });
      expect(result).toEqual(mockResult);
    });
  });

  describe('participateInSigning', () => {
    it('should return accepted response for async signing', async () => {
      // Mock the promise that won't resolve during the test
      mockApplicationService.participateInSigning.mockReturnValue(new Promise(() => {}));

      const dto = {
        sessionId: '550e8400-e29b-41d4-a716-446655440000',
        partyId: 'user123-server',
        joinToken: 'join-token-abc',
        messageHash: 'a'.repeat(64),
        publicKey: '03' + '0'.repeat(64),
      };

      const result = await controller.participateInSigning(dto);

      expect(result).toEqual({
        message: 'Signing participation started',
        sessionId: dto.sessionId,
        partyId: dto.partyId,
      });
    });
  });

  describe('participateInSigningSync', () => {
    it('should call application service and return result', async () => {
      const mockResult = {
        signature: '0'.repeat(128),
        messageHash: 'a'.repeat(64),
        publicKey: '03' + '0'.repeat(64),
      };

      mockApplicationService.participateInSigning.mockResolvedValue(mockResult);

      const dto = {
        sessionId: '550e8400-e29b-41d4-a716-446655440000',
        partyId: 'user123-server',
        joinToken: 'join-token-abc',
        messageHash: 'a'.repeat(64),
        publicKey: '03' + '0'.repeat(64),
      };

      const result = await controller.participateInSigningSync(dto);

      expect(mockApplicationService.participateInSigning).toHaveBeenCalledWith({
        sessionId: dto.sessionId,
        partyId: dto.partyId,
        joinToken: dto.joinToken,
        messageHash: dto.messageHash,
        publicKey: dto.publicKey,
      });
      expect(result).toEqual(mockResult);
    });
  });

  describe('rotateShare', () => {
    it('should return accepted response for async rotation', async () => {
      // Mock the promise that won't resolve during the test
      mockApplicationService.rotateShare.mockReturnValue(new Promise(() => {}));

      const dto = {
        sessionId: '550e8400-e29b-41d4-a716-446655440000',
        partyId: 'user123-server',
        joinToken: 'join-token-abc',
        publicKey: '03' + '0'.repeat(64),
      };

      const result = await controller.rotateShare(dto);

      expect(result).toEqual({
        message: 'Share rotation started',
        sessionId: dto.sessionId,
        partyId: dto.partyId,
      });
    });
  });
});
