package tutor

import akka.actor.ActorSystem
import akka.stream.ActorMaterializer
import akka.stream.scaladsl._
import com.typesafe.scalalogging.StrictLogging
import tutor.utils.BenchmarkUtil

import scala.collection.mutable.ArrayBuffer
import scala.concurrent.Future
import scala.util.{Failure, Success}

object CodebaseAnalyzerStreamApp extends App with DirectoryScanner with SourceCodeAnalyzer with ReportFormatter with StrictLogging {

  implicit val system = ActorSystem("CodebaseAnalyzer")
  implicit val materializer = ActorMaterializer()
  implicit val ec = system.dispatcher

  val path = args(0)
  val beginTime = BenchmarkUtil.recordStart(s"analyze $path with akka stream")
  val files = scan(path, PresetFilters.knownFileTypes, PresetFilters.ignoreFolders).iterator
  var errorProcessingFiles: ArrayBuffer[Throwable] = ArrayBuffer.empty

  val done = Source.fromIterator(() => files).mapAsync(8)(path => Future {
    processFile(path)
  }).fold(CodebaseInfo.empty) {
    (acc, trySourceCodeInfo) =>
      trySourceCodeInfo match {
        case Success(sourceCodeInfo) => acc + sourceCodeInfo
        case Failure(e) => {
          errorProcessingFiles += e
          acc
        }
      }
  }.runForeach(codebaseInfo => {
    println(format(codebaseInfo))
    println(s"there are ${errorProcessingFiles.size} files failed to process.")
  })
  done.onComplete { _ =>
    BenchmarkUtil.recordElapse(s"analyze $path with akka stream", beginTime)
    system.terminate()
  }
}