import { AuthUser } from "@/contexts/auth/domain";
import { IUseCaseError, UseCaseError } from "@/contexts/common/application/useCases";
import { IServerError } from "@/contexts/common/domain/errors";
import { IInfrastructureError, InfrastructureError } from "@/contexts/common/infrastructure";
import { ExpressController } from "@/contexts/common/infrastructure/express";
import { GetProfileUseCase as GetProfileLogoUseCase } from "@/contexts/profile/application/GetProfile.useCase";
import { IProfileContext } from "../../../Profile.context";
import { IGetProfileLogoPresenter } from "./presenter";

import { Request } from "express";

interface AuthenticatedRequest extends Request {
  user?: AuthUser;
}

export class GetProfileLogoController extends ExpressController {
  private useCase: GetProfileLogoUseCase;
  private presenter: IGetProfileLogoPresenter;
  private context: IProfileContext;

  constructor(
    props: {
      useCase: GetProfileLogoUseCase;
      presenter: IGetProfileLogoPresenter;
    },
    context: IProfileContext
  ) {
    super();

    const { useCase, presenter } = props;
    this.useCase = useCase;
    this.presenter = presenter;
    this.context = context;
  }

  async executeImpl(): Promise<any> {
    const req = this.req as AuthenticatedRequest;
    const user = <AuthUser>req.user;

    if (!user) {
      const errorMessage = "Unexpected missing user data";
      const infraError = InfrastructureError.create(
        InfrastructureError.UNEXCEPTED_ERROR,
        errorMessage
      );
      return this.internalServerError(errorMessage, infraError);
    }

    try {
      const profileOrError = await this.useCase.execute({
        userId: user.id,
      });

      if (profileOrError.isFailure) {
        return this._handleExecuteError(profileOrError.error);
      }

      const profile = profileOrError.object;
      const logo = this.presenter.map(profile, this.context);
      console.log(logo);
      return this.sendFile(logo);
    } catch (e: unknown) {
      return this.fail(e as IServerError);
    }
  }

  private _handleExecuteError(error: IUseCaseError) {
    let errorMessage: string;
    let infraError: IInfrastructureError;

    switch (error.code) {
      case UseCaseError.NOT_FOUND_ERROR:
        errorMessage = "User has no associated profile";

        infraError = InfrastructureError.create(
          InfrastructureError.RESOURCE_NOT_READY,
          errorMessage,
          error
        );

        return this.notFoundError(errorMessage, infraError);
        break;

      case UseCaseError.UNEXCEPTED_ERROR:
        errorMessage = error.message;

        infraError = InfrastructureError.create(
          InfrastructureError.UNEXCEPTED_ERROR,
          errorMessage,
          error
        );
        return this.internalServerError(errorMessage, infraError);
        break;

      default:
        errorMessage = error.message;
        return this.clientError(errorMessage);
    }
  }
}
