/*
 * Jooby https://jooby.io
 * Apache License Version 2.0 https://jooby.io/LICENSE.txt
 * Copyright 2014 Edgar Espina
 */
package kt

import examples.ABean
import examples.BBean
import examples.Bean
import io.jooby.StatusCode
import io.jooby.exception.StatusCodeException
import io.jooby.kt.Kooby
import java.util.*
import java.util.concurrent.Callable
import java.util.concurrent.CompletableFuture

class KtRouteReturnType :
  Kooby({
    fun something(): String {
      throw StatusCodeException(StatusCode.UNAUTHORIZED, "test")
    }

    fun someGeneric(): List<String> {
      return ArrayList()
    }

    @Throws(IllegalAccessException::class)
    fun throwsIAE(): String {
      throw IllegalAccessException("no-access")
    }

    path("/literal") {
      get("/1") { "str" }
      get("/2") { 57 }
      get("/3") {}
      get("/4") { true }
    }
    path("/call") {
      get("/1") { KtRouteReturnType() }
      get("/2") { Statics.computeStatic() }
      get("/3") {
        val instance = Instance()
        instance.newInstance(0, "c")
      }
      get("/4") { something() }
      get("/5") { throwsIAE() }
      get("/6") { someGeneric() }
    }
    path("/generic") {
      get("/1") {
        CompletableFuture.supplyAsync { ctx.query("n").intValue(1) }
          .thenApply { x -> x * 2 }
          .whenComplete { v, _ -> ctx.render(v) }
      }
      get("/2") {
        val future =
          CompletableFuture.completedFuture(0).thenApply { x -> x * 2 }.thenApply { x -> x * 3 }
        future
      }
      get("/3") { CompletableFuture.supplyAsync { "foo" } }
      get("/4") {
        val callable = Callable { Byte.MIN_VALUE }
        callable
      }
    }
    path("/localvar") {
      get("/1") {
        val q = ctx.query("q").value()
        q
      }
      get("/2") {
        val q = ctx.query("q").intValue()
        q
      }
      get("/3") {
        val values = ctx.path("v").toList().toTypedArray()
        values
      }
      get("/4") {
        val values = floatArrayOf(ctx.query("f1").floatValue(), ctx.query("f2").floatValue())
        values
      }
    }
    path("/complexType") {
      get("/1") { ctx.query("q").toList() }
      get("/2") {
        val q = ctx.query("q").toList()
        q
      }
      get("/3") {
        val listOfList: List<List<String>> = ArrayList()
        listOfList.stream().filter { obj: List<String>? -> Objects.nonNull(obj) }.toArray()
        listOfList
      }
    }
    path("/multipleTypes") {
      get("/1") {
        if (ctx.isInIoThread) {
          return@get ArrayList<String>()
        } else {
          return@get LinkedList<String>()
        }
      }
      get("/2") {
        if (ctx.isInIoThread) {
          return@get ABean()
        } else {
          return@get BBean()
        }
      }
      get("/3") {
        val user: Bean
        if (ctx.isInIoThread) {
          user = ABean()
          return@get user
        } else {
          user = BBean()
          return@get user
        }
      }
    }
    path("/array") {
      get("/1") { booleanArrayOf(true, false, false) }
      get("/2") {
        val listOfKtRouteReturnType = listOf<KtRouteReturnType>()
        listOfKtRouteReturnType
      }
      get("/3") { IntArray(0) }
      get("/4") { arrayOf("foo", "bar") }
    }
  }) {
  internal object Statics {
    fun computeStatic(): String {
      return "static"
    }
  }

  internal class Instance {
    fun newInstance(x: Int, v: String?): String {
      return v + x
    }
  }
}
