package eu.xeppaka.scalalearn

import akka.actor.ActorSystem
import akka.stream.{ActorMaterializer, OverflowStrategy}
import akka.stream.scaladsl.{Keep, Sink, Source}
import org.mongodb.scala.bson.BsonValue
import org.mongodb.scala.bson.collection.immutable.Document
import org.mongodb.scala.{MongoClient, MongoClientSettings, Observer, Subscription}
import org.mongodb.scala.model.Filters.{and, equal, gt, gte}

import scala.collection.mutable.ListBuffer
import scala.concurrent.duration.Duration
import scala.concurrent.{Await, Future, Promise}
import scala.concurrent.ExecutionContext.Implicits.global
import scala.util.{Failure, Success}

object Main {
  def main(args: Array[String]): Unit = {
    implicit val actorSystem: ActorSystem = ActorSystem()
    implicit val materializer: ActorMaterializer = ActorMaterializer()

    val mongoClient = MongoClient("mongodb://begencardcore:Heslo_1234@10.18.255.53:27017,10.18.255.163:27017,10.18.255.118:27017/begencardcore?replicaSet=cluster-lcs-dvp-mw")
    val db = mongoClient.getDatabase("begencardcore")
    val coll = db.getCollection("snapshot")

    val complete = Promise[Unit]()
    val batchSize = 1000
    var docs = ListBuffer[Document]()

    val onNextDoc = (doc: Document) => {
      coll
        .find[Document](equal("idAccount", doc.get("idAccount").get))
        .toFuture()
        .map(_.headOption)
        .andThen {
          case Success(value) => println(value)
          case Failure(exception) => println(exception)
        }
    }

    val queue = Source
      .queue[Document](1000, OverflowStrategy.backpressure)
      .mapAsync(10)(onNextDoc)
      .toMat(Sink.ignore)(Keep.left)
      .run()

    coll.find().subscribe(new Observer[Document] {
      var processed: Long = 0
      var subscription: Option[Subscription] = None
      var processingFuture: Future[Unit] = Future.unit

      override def onSubscribe(subscription: Subscription): Unit = {
        this.subscription = Some(subscription)
        subscription.request(batchSize)
      }

      override def onNext(result: Document): Unit = {
        queue
          .offer(result)
            .onComplete {
              case Success(offerResult) => println(offerResult)
              case Failure(exception) => println("offer failed")
            }
        processed = processed + 1

        if (processed == batchSize) {
          processed = 0
          subscription.get.request(batchSize)

          println(s"request next $batchSize...")
        }
      }

      override def onError(e: Throwable): Unit = ()
      override def onComplete(): Unit = complete.success(())
    })

    Await.ready(complete.future, Duration.Inf)
  }
}
