package wow.doge.mygame.implicits

import cats.Functor
import cats.Show
import cats.data.Kleisli
import cats.effect.Resource
import cats.syntax.show._
import monix.bio.IO
import monix.bio.Task
import monix.bio.UIO

trait CatsExtensions {
  implicit class KleisliCompanionExt(k: Kleisli.type) {
    def io[S, E, A](f: S => IO[E, A]): Kleisli[UIO, S, Either[E, A]] =
      k.apply(s => f(s).attempt)
  }
  implicit class KleisliExt[S, E, A](k: Kleisli[UIO, S, Either[E, A]]) {
    def runIO(s: S) = k.run(s).rethrow
  }
  implicit class ResourceCompanionExt(r: Resource.type) {
    //   def ioMake[UIO, R](acquire: )(release: ) = r.make()()
    def ioMake[E: Show, A](
        acquire: IO[E, A]
    )(
        release: A => UIO[Unit]
    )(implicit F: Functor[UIO]): Resource[UIO, Either[E, A]] =
      r.make(acquire.attempt)(a =>
        IO.fromEither(a)
          .onErrorHandleWith(err => IO.terminate(new Exception(err.show)))
          .flatMap(release)
      )

    val acq = IO(1).onErrorHandleWith(_ => IO.raiseError(""))

    val res =
      ioMake(acq)(_ => IO.unit)
    val result = res
      .use {
        case Left(value)  => Task(Left(value))
        case Right(value) => Task(Right(value))
      }
      .hideErrors
      .rethrow

    // IO.unit.bracket()
  }
  implicit class ResourceExt[E, A](k: Resource[UIO, Either[E, A]]) {
    // def runIO(s: S) = k.run(s).rethrow
    // k.use
    // : IO[E, B]
    // def useIO[B](f: Either[E, A] => IO[E, B]) =
    //   k.use(f).rethrow
    // type test[A] = Tuple2[*, Double]
    type IoResource[X, D] = Resource[IO[X, *], D]
    val x: Resource[IO[String, *], String] =
      Resource.make(IO.raiseError(""))(_ => IO.unit)
    // x.use(s => Task.unit)
    val x2: IoResource[String, String] =
      Resource.make(UIO(""))(_ => IO.unit)
  }
}
