package ru.yandex.atom.error

import java.util.concurrent.ExecutionException
import ru.yandex.atom.utils.actor.messages.{IExceptionResponse, IUserProblemResponse, IInternalProblemResponse, AbstractMessage}
import scala.reflect.ClassTag
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global

/**
 * @author avhaliullin
 */
object ErrorUtils {
  def unwrap(e: Throwable): Throwable = {
    e match {
      case x: ExecutionException => unwrap(x.getCause)
      case x => x
    }
  }

  def safeMapFutureMessage[Res <: AbstractMessage : ClassTag, SuccRes <: Res : ClassTag](respFuture: Future[Any]): Future[SuccRes] = {
    respFuture.mapTo[Res].flatMap {
      case errResp: IInternalProblemResponse => Future.failed(InternalException(errResp.problem))
      case errResp: IUserProblemResponse => Future.failed(UserException(errResp.problem))
      case errResp: IExceptionResponse => Future.failed(unwrap(errResp.problem))
      case success: SuccRes => Future.successful(success)
      case x => Future.failed(new IllegalArgumentException(
        // Ни за что не используйте тут ClassTag.runtimeClass.getCanonicalName() https://issues.scala-lang.org/browse/SI-2034
        s"Expecting ${implicitly[ClassTag[SuccRes]].toString()} or IFailureResponse or IUserProblemResponse, " +
          "but found " + String.valueOf(x)))
    }
  }
}
