import { Injectable, Inject } from '@nestjs/common';
import type { RequestAvatarGenerationInputDTO } from './dtos/RequestAvatarGenerationInputDTO';
import type { UploadMediaInputDTO } from './dtos/UploadMediaInputDTO';
import type { UpdateAvatarInputDTO } from './dtos/UpdateAvatarInputDTO';
import type { RequestAvatarGenerationOutputDTO } from './dtos/RequestAvatarGenerationOutputDTO';
import type { UploadMediaOutputDTO } from './dtos/UploadMediaOutputDTO';
import type { GetMediaOutputDTO } from './dtos/GetMediaOutputDTO';
import type { DeleteMediaOutputDTO } from './dtos/DeleteMediaOutputDTO';
import type { GetAvatarOutputDTO } from './dtos/GetAvatarOutputDTO';
import type { UpdateAvatarOutputDTO } from './dtos/UpdateAvatarOutputDTO';
import type { ValidateFaceInputDTO } from './dtos/ValidateFaceInputDTO';
import type { ValidateFaceOutputDTO } from './dtos/ValidateFaceOutputDTO';
import type { RacingSuitColor } from '@core/media/domain/types/AvatarGenerationRequest';
import type { MulterFile } from './types/MulterFile';

type RequestAvatarGenerationInput = RequestAvatarGenerationInputDTO;
type UploadMediaInput = UploadMediaInputDTO;
type UpdateAvatarInput = UpdateAvatarInputDTO;

// Use cases
import { RequestAvatarGenerationUseCase } from '@core/media/application/use-cases/RequestAvatarGenerationUseCase';
import { UploadMediaUseCase } from '@core/media/application/use-cases/UploadMediaUseCase';
import { GetMediaUseCase } from '@core/media/application/use-cases/GetMediaUseCase';
import { DeleteMediaUseCase } from '@core/media/application/use-cases/DeleteMediaUseCase';
import { GetAvatarUseCase } from '@core/media/application/use-cases/GetAvatarUseCase';
import { UpdateAvatarUseCase } from '@core/media/application/use-cases/UpdateAvatarUseCase';

// Presenters
import { RequestAvatarGenerationPresenter } from './presenters/RequestAvatarGenerationPresenter';
import { UploadMediaPresenter } from './presenters/UploadMediaPresenter';
import { GetMediaPresenter } from './presenters/GetMediaPresenter';
import { DeleteMediaPresenter } from './presenters/DeleteMediaPresenter';
import { GetAvatarPresenter } from './presenters/GetAvatarPresenter';
import { UpdateAvatarPresenter } from './presenters/UpdateAvatarPresenter';

import {
  REQUEST_AVATAR_GENERATION_USE_CASE_TOKEN,
  UPLOAD_MEDIA_USE_CASE_TOKEN,
  GET_MEDIA_USE_CASE_TOKEN,
  DELETE_MEDIA_USE_CASE_TOKEN,
  GET_AVATAR_USE_CASE_TOKEN,
  UPDATE_AVATAR_USE_CASE_TOKEN,
  LOGGER_TOKEN,
} from './MediaTokens';
import type { Logger } from '@core/shared/application';

@Injectable()
export class MediaService {
  constructor(
    @Inject(REQUEST_AVATAR_GENERATION_USE_CASE_TOKEN)
    private readonly requestAvatarGenerationUseCase: RequestAvatarGenerationUseCase,
    @Inject(UPLOAD_MEDIA_USE_CASE_TOKEN)
    private readonly uploadMediaUseCase: UploadMediaUseCase,
    @Inject(GET_MEDIA_USE_CASE_TOKEN)
    private readonly getMediaUseCase: GetMediaUseCase,
    @Inject(DELETE_MEDIA_USE_CASE_TOKEN)
    private readonly deleteMediaUseCase: DeleteMediaUseCase,
    @Inject(GET_AVATAR_USE_CASE_TOKEN)
    private readonly getAvatarUseCase: GetAvatarUseCase,
    @Inject(UPDATE_AVATAR_USE_CASE_TOKEN)
    private readonly updateAvatarUseCase: UpdateAvatarUseCase,
    @Inject(LOGGER_TOKEN)
    private readonly logger: Logger,
    private readonly requestAvatarGenerationPresenter: RequestAvatarGenerationPresenter,
    private readonly uploadMediaPresenter: UploadMediaPresenter,
    private readonly getMediaPresenter: GetMediaPresenter,
    private readonly deleteMediaPresenter: DeleteMediaPresenter,
    private readonly getAvatarPresenter: GetAvatarPresenter,
    private readonly updateAvatarPresenter: UpdateAvatarPresenter,
  ) {}

  async requestAvatarGeneration(
    input: RequestAvatarGenerationInput,
  ): Promise<RequestAvatarGenerationOutputDTO> {
    this.logger.debug('[MediaService] Requesting avatar generation.');

    const result = await this.requestAvatarGenerationUseCase.execute({
      userId: input.userId,
      facePhotoData: input.facePhotoData,
      suitColor: input.suitColor as RacingSuitColor,
    });

    if (result.isErr()) {
      const error = result.unwrapErr();
      return {
        success: false,
        requestId: '',
        avatarUrls: [],
        errorMessage: error.details?.message ?? 'Failed to request avatar generation',
      };
    }

    return this.requestAvatarGenerationPresenter.responseModel;
  }

  async uploadMedia(
    input: UploadMediaInput & { file: MulterFile } & { userId?: string; metadata?: Record<string, unknown> },
  ): Promise<UploadMediaOutputDTO> {
    this.logger.debug('[MediaService] Uploading media.');

    const result = await this.uploadMediaUseCase.execute({
      file: input.file,
      uploadedBy: input.userId ?? '',
      metadata: input.metadata || {},
    });

    if (result.isErr()) {
      const error = result.unwrapErr();
      return {
        success: false,
        error: error.details?.message ?? 'Upload failed',
      };
    }

    return this.uploadMediaPresenter.responseModel;
  }

  async getMedia(mediaId: string): Promise<GetMediaOutputDTO | null> {
    this.logger.debug(`[MediaService] Getting media: ${mediaId}`);

    const result = await this.getMediaUseCase.execute({ mediaId });

    if (result.isErr()) {
      const error = result.unwrapErr();
      if (error.code === 'MEDIA_NOT_FOUND') {
        return null;
      }
      throw new Error(error.details?.message ?? 'Failed to get media');
    }

    return this.getMediaPresenter.responseModel;
  }

  async deleteMedia(mediaId: string): Promise<DeleteMediaOutputDTO> {
    this.logger.debug(`[MediaService] Deleting media: ${mediaId}`);

    const result = await this.deleteMediaUseCase.execute({ mediaId });

    if (result.isErr()) {
      const error = result.unwrapErr();
      return {
        success: false,
        error: error.details?.message ?? 'Failed to delete media',
      };
    }

    return this.deleteMediaPresenter.responseModel;
  }

  async getAvatar(driverId: string): Promise<GetAvatarOutputDTO | null> {
    this.logger.debug(`[MediaService] Getting avatar for driver: ${driverId}`);

    const result = await this.getAvatarUseCase.execute({ driverId });

    if (result.isErr()) {
      const error = result.unwrapErr();
      if (error.code === 'AVATAR_NOT_FOUND') {
        return null;
      }
      throw new Error(error.details?.message ?? 'Failed to get avatar');
    }

    return this.getAvatarPresenter.responseModel;
  }

  async updateAvatar(driverId: string, input: UpdateAvatarInput): Promise<UpdateAvatarOutputDTO> {
    this.logger.debug(`[MediaService] Updating avatar for driver: ${driverId}`);

    // Handle null avatarUrl - this would mean removing the avatar
    if (input.avatarUrl === null) {
      // For now, we'll treat null as an error since the use case requires a URL
      // In a complete implementation, this would trigger avatar removal
      return {
        success: false,
        error: 'Avatar URL cannot be null',
      };
    }

    const result = await this.updateAvatarUseCase.execute({
      driverId,
      mediaUrl: input.avatarUrl,
    });

    if (result.isErr()) {
      const error = result.unwrapErr();
      return {
        success: false,
        error: error.details?.message ?? 'Failed to update avatar',
      };
    }

    return this.updateAvatarPresenter.responseModel;
  }

  async validateFacePhoto(input: ValidateFaceInputDTO): Promise<ValidateFaceOutputDTO> {
    this.logger.debug('[MediaService] Validating face photo.');

    // Simple validation: check if it's a valid base64 image
    if (!input.imageData || !input.imageData.startsWith('data:image/')) {
      return { isValid: false, errorMessage: 'Invalid image data' };
    }

    // Check file size (rough estimate from base64 length)
    const base64Length = input.imageData.length;
    const fileSizeInBytes = (base64Length * 3) / 4; // Rough estimate
    const maxSize = 5 * 1024 * 1024; // 5MB

    if (fileSizeInBytes > maxSize) {
      return { isValid: false, errorMessage: 'Image too large (max 5MB)' };
    }

    return { isValid: true };
  }
}
