package com.avast.marathon.plugin.vault

import java.lang.reflect.Type
import java.time.{Duration, Instant}

import feign.codec.{Decoder, StringDecoder}
import feign.{Feign, Param, RequestLine, Response}
import feign.gson.GsonDecoder

import scala.collection.JavaConverters._

object MesosAgentClient {
  private val contentTypeHeader = "Content-Type"
  private val gson = new GsonDecoder
  private val string = new StringDecoder

  def apply(agentUrl: String): MesosAgentClient = {
    Feign.builder()
      .decoder(new Decoder {
        override def decode(response: Response, `type`: Type): AnyRef = {
          if (response.headers().containsKey(contentTypeHeader)) {
            val value = response.headers().get(contentTypeHeader).asScala.head
            if (value.contains("json")) return gson.decode(response, `type`)
          }
          string.decode(response, `type`)
        }
      })
      .target(classOf[MesosAgentClient], agentUrl)
  }

  implicit class MesosAgentClientEx(agentClient: MesosAgentClient) {
    def waitForStdOutContentsMatch(envVarName: String, executor: MesosExecutor, fn: String => Option[String], timeout: Duration): String = {
      val stdOutPath = s"${executor.directory}/stdout"
      var matchOption: Option[String] = None
      var stdOut: String = null
      val maxTime = Instant.now().plus(timeout)
      do {
        if (Instant.now().compareTo(maxTime) > 1) {
          throw new RuntimeException("Timed out when waiting for task stdout to match.")
        }
        stdOut = agentClient.download(stdOutPath)
        matchOption = EnvAppCmd.extractEnvValue(envVarName, stdOut)
      } while (matchOption.isEmpty)
      matchOption.get
    }
  }
}

trait MesosAgentClient {
  @RequestLine("GET /state")
  def fetchState(): MesosAgentState
  @RequestLine("GET /files/download?path={path}")
  def download(@Param("path") path: String): String
}

case class MesosFramework(id: String, executors: Array[MesosExecutor])
case class MesosExecutor(id: String, name: String, directory: String)
case class MesosAgentState(frameworks: Array[MesosFramework])