import { AdminVoteSession } from '../../domain/entities/AdminVoteSession';
import { AdminVoteSessionRepository } from '../../domain/repositories/AdminVoteSessionRepository';
import { OpenAdminVoteSessionInput, OpenAdminVoteSessionOutput } from '../dtos/AdminVoteSessionDto';

/**
 * Use Case: OpenAdminVoteSessionUseCase
 * 
 * Opens a new admin vote session for a league.
 * Follows CQRS Light: command side operation.
 * 
 * Per plans section 7.1.1
 */
export class OpenAdminVoteSessionUseCase {
  constructor(
    private readonly adminVoteSessionRepository: AdminVoteSessionRepository,
  ) {}

  async execute(input: OpenAdminVoteSessionInput): Promise<OpenAdminVoteSessionOutput> {
    try {
      // Validate input
      const errors = this.validateInput(input);
      if (errors.length > 0) {
        return {
          success: false,
          voteSessionId: input.voteSessionId,
          errors,
        };
      }

      // Check if session already exists
      const existing = await this.adminVoteSessionRepository.findById(input.voteSessionId);
      if (existing) {
        return {
          success: false,
          voteSessionId: input.voteSessionId,
          errors: ['Vote session with this ID already exists'],
        };
      }

      // Check for overlapping active sessions for this admin in this league
      const activeSessions = await this.adminVoteSessionRepository.findActiveForAdmin(
        input.adminId,
        input.leagueId
      );

      const startDate = new Date(input.startDate);
      const endDate = new Date(input.endDate);

      for (const session of activeSessions) {
        // Check for overlap
        if (
          (startDate >= session.startDate && startDate <= session.endDate) ||
          (endDate >= session.startDate && endDate <= session.endDate) ||
          (startDate <= session.startDate && endDate >= session.endDate)
        ) {
          return {
            success: false,
            voteSessionId: input.voteSessionId,
            errors: ['Active vote session already exists for this admin in this league with overlapping dates'],
          };
        }
      }

      // Create the vote session
      const session = AdminVoteSession.create({
        voteSessionId: input.voteSessionId,
        leagueId: input.leagueId,
        adminId: input.adminId,
        startDate,
        endDate,
        eligibleVoters: input.eligibleVoters,
      });

      // Save to repository
      await this.adminVoteSessionRepository.save(session);

      return {
        success: true,
        voteSessionId: input.voteSessionId,
      };

    } catch (error) {
      const errorMsg = error instanceof Error ? error.message : 'Unknown error';
      return {
        success: false,
        voteSessionId: input.voteSessionId,
        errors: [`Failed to open vote session: ${errorMsg}`],
      };
    }
  }

  private validateInput(input: OpenAdminVoteSessionInput): string[] {
    const errors: string[] = [];

    if (!input.voteSessionId || input.voteSessionId.trim().length === 0) {
      errors.push('voteSessionId is required');
    }

    if (!input.leagueId || input.leagueId.trim().length === 0) {
      errors.push('leagueId is required');
    }

    if (!input.adminId || input.adminId.trim().length === 0) {
      errors.push('adminId is required');
    }

    if (!input.startDate) {
      errors.push('startDate is required');
    }

    if (!input.endDate) {
      errors.push('endDate is required');
    }

    if (input.startDate && input.endDate) {
      const startDate = new Date(input.startDate);
      const endDate = new Date(input.endDate);

      if (isNaN(startDate.getTime())) {
        errors.push('startDate must be a valid date');
      }

      if (isNaN(endDate.getTime())) {
        errors.push('endDate must be a valid date');
      }

      if (startDate >= endDate) {
        errors.push('startDate must be before endDate');
      }
    }

    if (!input.eligibleVoters || input.eligibleVoters.length === 0) {
      errors.push('At least one eligible voter is required');
    } else {
      // Check for duplicates
      const uniqueVoters = new Set(input.eligibleVoters);
      if (uniqueVoters.size !== input.eligibleVoters.length) {
        errors.push('Duplicate eligible voters are not allowed');
      }
    }

    return errors;
  }
}
