import type { TeamJoinRequest, TeamMembership } from '@core/racing/domain/types/TeamMembership';
import type { Logger } from '@core/shared/domain/Logger';
import { beforeEach, describe, expect, it, vi } from 'vitest';
import { InMemoryTeamMembershipRepository } from './InMemoryTeamMembershipRepository';

/* eslint-disable @typescript-eslint/no-explicit-any */

describe('InMemoryTeamMembershipRepository', () => {
  let repository: InMemoryTeamMembershipRepository;
  let mockLogger: Logger;

  beforeEach(() => {
    mockLogger = {
      debug: vi.fn(),
      info: vi.fn(),
      warn: vi.fn(),
      error: vi.fn(),
    };
    repository = new InMemoryTeamMembershipRepository(mockLogger);
  });

  const createTestMembership = (
    teamId: string,
    driverId: string,
    role: 'owner' | 'manager' | 'driver' = 'driver',
    status: 'active' | 'pending' | 'none' = 'active',
    joinedAt: Date = new Date()
  ): TeamMembership => ({
    teamId,
    driverId,
    role,
    status,
    joinedAt,
  });

  const createTestJoinRequest = (
    id: string,
    teamId: string,
    driverId: string,
    requestedAt: Date = new Date(),
    message?: string
  ): TeamJoinRequest => ({
    id,
    teamId,
    driverId,
    requestedAt,
    ...(message !== undefined ? { message } : {}),
  });

  describe('constructor', () => {
    it('should initialize with logger', () => {
      expect(repository).toBeDefined();
      expect(mockLogger.info).toHaveBeenCalledWith('InMemoryTeamMembershipRepository initialized.');
    });
  });

  describe('getMembership', () => {
    it('should return membership if found', async () => {
      const membership = createTestMembership('team1', 'driver1');
      await repository.saveMembership(membership);

      const result = await repository.getMembership('team1', 'driver1');
      expect(result).toEqual(membership);
    });

    it('should return null if membership not found', async () => {
      const result = await repository.getMembership('team1', 'driver1');
      expect(result).toBeNull();
    });

    it('should return null if team has no memberships', async () => {
      const result = await repository.getMembership('nonexistent', 'driver1');
      expect(result).toBeNull();
    });
  });

  describe('getActiveMembershipForDriver', () => {
    it('should return active membership for driver', async () => {
      const activeMembership = createTestMembership('team1', 'driver1', 'driver', 'active');
      const pendingMembership = createTestMembership('team2', 'driver1', 'driver', 'pending');
      await repository.saveMembership(activeMembership);
      await repository.saveMembership(pendingMembership);

      const result = await repository.getActiveMembershipForDriver('driver1');
      expect(result).toEqual(activeMembership);
    });

    it('should return null if no active membership', async () => {
      const pendingMembership = createTestMembership('team1', 'driver1', 'driver', 'pending');
      await repository.saveMembership(pendingMembership);

      const result = await repository.getActiveMembershipForDriver('driver1');
      expect(result).toBeNull();
    });

    it('should return null if driver has no memberships', async () => {
      const result = await repository.getActiveMembershipForDriver('driver1');
      expect(result).toBeNull();
    });
  });

  describe('getTeamMembers', () => {
    it('should return all members for team', async () => {
      const member1 = createTestMembership('team1', 'driver1');
      const member2 = createTestMembership('team1', 'driver2');
      const member3 = createTestMembership('team2', 'driver3');
      await repository.saveMembership(member1);
      await repository.saveMembership(member2);
      await repository.saveMembership(member3);

      const result = await repository.getTeamMembers('team1');
      expect(result).toHaveLength(2);
      expect(result).toContain(member1);
      expect(result).toContain(member2);
    });

    it('should return empty array if team has no members', async () => {
      const result = await repository.getTeamMembers('team1');
      expect(result).toEqual([]);
    });
  });

  describe('countByTeamId', () => {
    it('should count active members for team', async () => {
      const active1 = createTestMembership('team1', 'driver1', 'driver', 'active');
      const active2 = createTestMembership('team1', 'driver2', 'driver', 'active');
      const pending = createTestMembership('team1', 'driver3', 'driver', 'pending');
      await repository.saveMembership(active1);
      await repository.saveMembership(active2);
      await repository.saveMembership(pending);

      const result = await repository.countByTeamId('team1');
      expect(result).toBe(2);
    });

    it('should return 0 if team has no active members', async () => {
      const pending = createTestMembership('team1', 'driver1', 'driver', 'pending');
      await repository.saveMembership(pending);

      const result = await repository.countByTeamId('team1');
      expect(result).toBe(0);
    });

    it('should return 0 if team has no members', async () => {
      const result = await repository.countByTeamId('team1');
      expect(result).toBe(0);
    });
  });

  describe('saveMembership', () => {
    it('should save new membership', async () => {
      const membership = createTestMembership('team1', 'driver1');
      const result = await repository.saveMembership(membership);
      expect(result).toEqual(membership);
      expect(mockLogger.info).toHaveBeenCalledWith('[saveMembership] Success - created new membership for team: team1, driver: driver1.');
    });

    it('should update existing membership', async () => {
      const membership = createTestMembership('team1', 'driver1', 'driver', 'active');
      await repository.saveMembership(membership);
      const updated = createTestMembership('team1', 'driver1', 'manager', 'active');
      const result = await repository.saveMembership(updated);
      expect(result).toEqual(updated);
      expect(mockLogger.info).toHaveBeenCalledWith('[saveMembership] Success - updated existing membership for team: team1, driver: driver1.');
    });
  });

  describe('removeMembership', () => {
    it('should remove existing membership', async () => {
      const membership = createTestMembership('team1', 'driver1');
      await repository.saveMembership(membership);
      await repository.removeMembership('team1', 'driver1');
      const found = await repository.getMembership('team1', 'driver1');
      expect(found).toBeNull();
      expect(mockLogger.info).toHaveBeenCalledWith('[removeMembership] Success - removed membership for team: team1, driver: driver1.');
    });

    it('should log warning if membership not found', async () => {
      await repository.removeMembership('team1', 'driver1');
      expect(mockLogger.warn).toHaveBeenCalledWith('[removeMembership] No membership list found for team: team1. Cannot remove.');
    });
  });

  describe('getJoinRequests', () => {
    it('should return join requests for team', async () => {
      const request1 = createTestJoinRequest('req1', 'team1', 'driver1');
      const request2 = createTestJoinRequest('req2', 'team1', 'driver2');
      const request3 = createTestJoinRequest('req3', 'team2', 'driver3');
      await repository.saveJoinRequest(request1);
      await repository.saveJoinRequest(request2);
      await repository.saveJoinRequest(request3);

      const result = await repository.getJoinRequests('team1');
      expect(result).toHaveLength(2);
      expect(result).toContain(request1);
      expect(result).toContain(request2);
    });

    it('should return empty array if team has no requests', async () => {
      const result = await repository.getJoinRequests('team1');
      expect(result).toEqual([]);
    });
  });

  describe('saveJoinRequest', () => {
    it('should save new join request', async () => {
      const request = createTestJoinRequest('req1', 'team1', 'driver1');
      const result = await repository.saveJoinRequest(request);
      expect(result).toEqual(request);
      expect(mockLogger.info).toHaveBeenCalledWith('[saveJoinRequest] Success - created new join request: req1.');
    });

    it('should update existing join request', async () => {
      const request = createTestJoinRequest('req1', 'team1', 'driver1');
      await repository.saveJoinRequest(request);
      const updated = createTestJoinRequest('req1', 'team1', 'driver1', new Date(), 'updated message');
      const result = await repository.saveJoinRequest(updated);
      expect(result).toEqual(updated);
      expect(mockLogger.info).toHaveBeenCalledWith('[saveJoinRequest] Success - updated existing join request: req1.');
    });
  });

  describe('removeJoinRequest', () => {
    it('should remove join request by id', async () => {
      const request = createTestJoinRequest('req1', 'team1', 'driver1');
      await repository.saveJoinRequest(request);
      await repository.removeJoinRequest('req1');
      const requests = await repository.getJoinRequests('team1');
      expect(requests).toHaveLength(0);
      expect(mockLogger.info).toHaveBeenCalledWith('[removeJoinRequest] Success - removed join request req1 from team team1.');
    });

    it('should log warning if request not found', async () => {
      await repository.removeJoinRequest('req1');
      expect(mockLogger.warn).toHaveBeenCalledWith('[removeJoinRequest] Not found - join request with ID req1 not found for removal.');
    });
  });
});