import { IAdminVoteSessionRepository } from '../../domain/repositories/IAdminVoteSessionRepository';
import { CastAdminVoteInput, CastAdminVoteOutput } from '../dtos/AdminVoteSessionDto';

/**
 * Use Case: CastAdminVoteUseCase
 * 
 * Casts a vote in an active admin vote session.
 * Follows CQRS Light: command side operation.
 * 
 * Per plans section 7.1.1
 */
export class CastAdminVoteUseCase {
  constructor(
    private readonly adminVoteSessionRepository: IAdminVoteSessionRepository,
  ) {}

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

      // Load the vote session
      const session = await this.adminVoteSessionRepository.findById(input.voteSessionId);
      if (!session) {
        return {
          success: false,
          voteSessionId: input.voteSessionId,
          voterId: input.voterId,
          errors: ['Vote session not found'],
        };
      }

      // Check if session is open
      const voteTime = input.votedAt ? new Date(input.votedAt) : new Date();
      if (!session.isVotingWindowOpen(voteTime)) {
        return {
          success: false,
          voteSessionId: input.voteSessionId,
          voterId: input.voterId,
          errors: ['Vote session is not open for voting'],
        };
      }

      // Cast the vote
      session.castVote(input.voterId, input.positive, voteTime);

      // Save updated session
      await this.adminVoteSessionRepository.save(session);

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

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

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

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

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

    if (typeof input.positive !== 'boolean') {
      errors.push('positive must be a boolean value');
    }

    if (input.votedAt) {
      const votedAt = new Date(input.votedAt);
      if (isNaN(votedAt.getTime())) {
        errors.push('votedAt must be a valid date if provided');
      }
    }

    return errors;
  }
}
