package com.octaldata.endpoints.integration

import com.octaldata.datastore.IntegrationDatastore
import com.octaldata.domain.integrations.Integration
import com.octaldata.domain.integrations.IntegrationConfig
import com.octaldata.domain.integrations.IntegrationId
import com.octaldata.domain.integrations.IntegrationName
import com.octaldata.domain.integrations.IntegrationType
import com.octaldata.endpoints.withIntegrationId
import com.octaldata.streamops.ktor.withRequest
import com.sksamuel.tabby.results.flatMap
import io.ktor.application.call
import io.ktor.http.HttpStatusCode
import io.ktor.response.respond
import io.ktor.routing.Route
import io.ktor.routing.delete
import io.ktor.routing.get
import io.ktor.routing.post
import io.ktor.routing.put
import io.ktor.util.getOrFail
import mu.KotlinLogging

private val logger = KotlinLogging.logger { }

fun Route.integrationEndpoints(
   datastore: IntegrationDatastore,
) {

   // returns all integrations
   get("/api/integration") {
      datastore.findAll().fold(
         { call.respond(HttpStatusCode.OK, it) },
         { call.respond(HttpStatusCode.InternalServerError, it) }
      )
   }

   // adds a new integration
   post("/api/integration") {
      withRequest<AddIntegrationRequest> { req ->
         runCatching {
            when (req.type) {
               IntegrationType.Datadog -> IntegrationConfig.Datadog(
                  req.apiKey ?: "",
                  req.batchSize?.toIntOrNull(),
                  req.flushSeconds?.toIntOrNull()
               )
               IntegrationType.Grafana -> IntegrationConfig.Grafana(
                  req.apiKey ?: "",
               )
               IntegrationType.Humio -> IntegrationConfig.Humio(
                  req.apiKey ?: "",
               )
               IntegrationType.Kairos -> IntegrationConfig.EmptyConfig
               IntegrationType.Snowflake -> IntegrationConfig.Snowflake(
                  serverName = req.serverName!!,
                  user = req.user!!,
                  password = req.password!!,
               )
               IntegrationType.Prometheus -> IntegrationConfig.Prometheus(
                  host = req.host!!,
                  port = req.port!!,
               )
               IntegrationType.AppOptics -> IntegrationConfig.Humio(
                  req.apiKey ?: "",
               )
            }
         }.flatMap { config ->
            datastore.insert(
               Integration(
                  id = IntegrationId.generate(),
                  name = req.name,
                  type = req.type,
                  config = config,
               )
            )
         }.fold(
            { call.respond(HttpStatusCode.OK, it) },
            {
               logger.warn(it) { "Error adding integration" }
               call.respond(HttpStatusCode.InternalServerError, it)
            }
         )
      }
   }

   // updates an existing integration
   put("/api/integration/{integrationId}") {
      withRequest<UpdateIntegrationRequest> { req ->
         val i = datastore.getById(IntegrationId(call.parameters.getOrFail("integrationId"))).getOrThrow()!!
         runCatching {
            when (i.type) {
               IntegrationType.Datadog -> IntegrationConfig.Datadog(
                  req.apiKey ?: "",
                  req.batchSize?.toIntOrNull(),
                  req.flushSeconds?.toIntOrNull()
               )
               IntegrationType.Grafana -> IntegrationConfig.Grafana(
                  req.apiKey ?: "",
               )
               IntegrationType.Humio -> IntegrationConfig.Humio(
                  req.apiKey ?: "",
               )
               IntegrationType.Kairos -> IntegrationConfig.EmptyConfig
               IntegrationType.Snowflake -> IntegrationConfig.Snowflake(
                  serverName = req.serverName!!,
                  user = req.user!!,
                  password = req.password!!,
               )
               IntegrationType.Prometheus -> IntegrationConfig.Prometheus(
                  host = req.host!!,
                  port = req.port!!,
               )
               IntegrationType.AppOptics -> IntegrationConfig.Humio(
                  req.apiKey ?: "",
               )
            }
         }.map { config ->
            datastore.update(i.id, req.name, config)
         }
      }.fold(
         { call.respond(HttpStatusCode.OK, it) },
         {
            logger.warn(it) { "Error adding integration" }
            call.respond(HttpStatusCode.InternalServerError, it)
         }
      )
   }

   // deletes an integration identified by the given id
   delete("/api/integration/{integrationId}") {
      withIntegrationId { integrationId ->
         datastore.delete(integrationId).fold(
            { call.respond(HttpStatusCode.OK, it) },
            { call.respond(HttpStatusCode.InternalServerError, it) }
         )
      }
   }
}

data class AddIntegrationRequest(
   val name: IntegrationName,
   val type: IntegrationType,
   val apiKey: String?,
   val host: String?,
   val port: Int?,
   val batchSize: String?,
   val flushSeconds: String?,
   val serverName: String?,
   val user: String?,
   val password: String?,
)

data class UpdateIntegrationRequest(
   val name: IntegrationName,
   val apiKey: String?,
   val host: String?,
   val port: Int?,
   val batchSize: String?,
   val flushSeconds: String?,
   val serverName: String?,
   val user: String?,
   val password: String?,
)