import type { UseCase, Logger } from '@core/shared/application';
import type { IAvatarGenerationRepository } from '../../domain/repositories/IAvatarGenerationRepository';
import type { FaceValidationPort } from '../ports/FaceValidationPort';
import type { AvatarGenerationPort } from '../ports/AvatarGenerationPort';
import type { IRequestAvatarGenerationPresenter, RequestAvatarGenerationResultDTO } from '../presenters/IRequestAvatarGenerationPresenter';
import { AvatarGenerationRequest } from '../../domain/entities/AvatarGenerationRequest';
import type { RacingSuitColor, AvatarStyle } from '../../domain/types/AvatarGenerationRequest';

export interface RequestAvatarGenerationCommand {
  userId: string;
  facePhotoData: string; // Base64 encoded image data
  suitColor: RacingSuitColor;
  style?: AvatarStyle;
}

export class RequestAvatarGenerationUseCase
  implements UseCase<RequestAvatarGenerationCommand, RequestAvatarGenerationResultDTO, any, IRequestAvatarGenerationPresenter> {
  constructor(
    private readonly avatarRepository: IAvatarGenerationRepository,
    private readonly faceValidation: FaceValidationPort,
    private readonly avatarGeneration: AvatarGenerationPort,
    private readonly logger: Logger,
  ) {}

  async execute(command: RequestAvatarGenerationCommand, presenter: IRequestAvatarGenerationPresenter): Promise<void> {
    presenter.reset();
    this.logger.debug(
      `Executing RequestAvatarGenerationUseCase for userId: ${command.userId}`,
      command,
    );

    try {
      // Create the generation request
      const requestId = this.generateId();
      const request = AvatarGenerationRequest.create({
        id: requestId,
        userId: command.userId,
        facePhotoUrl: `data:image/jpeg;base64,${command.facePhotoData}`,
        suitColor: command.suitColor,
        ...(command.style ? { style: command.style } : {}),
      });

      this.logger.info(`Avatar generation request created with ID: ${requestId}`);

      // Mark as validating
      request.markAsValidating();
      await this.avatarRepository.save(request);
      this.logger.debug(`Request ${requestId} marked as validating.`);

      // Validate the face photo
      const validationResult = await this.faceValidation.validateFacePhoto(command.facePhotoData);
      this.logger.debug(
        `Face validation result for request ${requestId}:`,
        validationResult,
      );
      
      if (!validationResult.isValid) {
        const errorMessage = validationResult.errorMessage || 'Face validation failed';
        request.fail(errorMessage);
        await this.avatarRepository.save(request);
        this.logger.error(`Face validation failed for request ${requestId}: ${errorMessage}`);
        presenter.present({
          requestId,
          status: 'failed',
          errorMessage: validationResult.errorMessage || 'Please upload a clear photo of your face',
        });
        return;
      }

      if (!validationResult.hasFace) {
        const errorMessage = 'No face detected in the image';
        request.fail(errorMessage);
        await this.avatarRepository.save(request);
        this.logger.error(`No face detected for request ${requestId}: ${errorMessage}`);
        presenter.present({
          requestId,
          status: 'failed',
          errorMessage: 'No face detected. Please upload a photo that clearly shows your face.',
        });
        return;
      }

      if (validationResult.faceCount > 1) {
        const errorMessage = 'Multiple faces detected';
        request.fail(errorMessage);
        await this.avatarRepository.save(request);
        this.logger.error(`Multiple faces detected for request ${requestId}: ${errorMessage}`);
        presenter.present({
          requestId,
          status: 'failed',
          errorMessage: 'Multiple faces detected. Please upload a photo with only your face.',
        });
        return;
      }
      this.logger.info(`Face validation successful for request ${requestId}.`);

      // Mark as generating
      request.markAsGenerating();
      await this.avatarRepository.save(request);
      this.logger.debug(`Request ${requestId} marked as generating.`);

      // Generate avatars
      const generationResult = await this.avatarGeneration.generateAvatars({
        facePhotoUrl: request.facePhotoUrl.value,
        prompt: request.buildPrompt(),
        suitColor: request.suitColor,
        style: request.style,
        count: 3, // Generate 3 options
      });
      this.logger.debug(
        `Avatar generation service result for request ${requestId}:`,
        generationResult,
      );

      if (!generationResult.success) {
        const errorMessage = generationResult.errorMessage || 'Avatar generation failed';
        request.fail(errorMessage);
        await this.avatarRepository.save(request);
        this.logger.error(`Avatar generation failed for request ${requestId}: ${errorMessage}`);
        presenter.present({
          requestId,
          status: 'failed',
          errorMessage: generationResult.errorMessage || 'Failed to generate avatars. Please try again.',
        });
        return;
      }

      // Complete with generated avatars
      const avatarUrls = generationResult.avatars.map(a => a.url);
      request.completeWithAvatars(avatarUrls);
      await this.avatarRepository.save(request);
      this.logger.info(`Avatar generation completed successfully for request ${requestId}.`);

      presenter.present({
        requestId,
        status: 'completed',
        avatarUrls,
      });
    } catch (error) {
      this.logger.error(
        `An unexpected error occurred during avatar generation for userId: ${command.userId}`,
        error as Error,
      );
      // Re-throw or return a generic error, depending on desired error handling strategy
      throw error;
    }
  }

  private generateId(): string {
    if (typeof crypto !== 'undefined' && crypto.randomUUID) {
      return crypto.randomUUID();
    }
    return 'avatar-' + Date.now().toString(36) + Math.random().toString(36).substr(2, 9);
  }
}