package com.octaldata.datastore.metric

import com.octaldata.datastore.JdbcCoroutineTemplate
import com.octaldata.domain.DeploymentId
import com.octaldata.domain.integrations.IntegrationId
import com.octaldata.domain.metrics.Metric
import com.octaldata.domain.metrics.MetricId
import com.octaldata.domain.metrics.MetricKey
import com.octaldata.domain.metrics.MetricStatus
import com.octaldata.domain.metrics.MetricType
import com.octaldata.domain.metrics.toTags
import org.springframework.jdbc.core.RowMapper
import javax.sql.DataSource

class MetricDatastore(ds: DataSource) {

   private val template = JdbcCoroutineTemplate(ds)

   private val mapper = RowMapper { rs, _ ->
      Metric(
         id = MetricId(rs.getString("id")),
         deploymentId = DeploymentId(rs.getString("deployment_id")),
         status = MetricStatus.valueOf(rs.getString("status")),
         key = MetricKey(rs.getString("keyname")),
         type = MetricType.valueOf(rs.getString("type")),
         query = rs.getString("query"),
         tags = rs.getString("tags")?.toTags() ?: emptyMap(),
         integrationIds = rs.getString("integration_ids")
            .split(',')
            .filter { it.isNotBlank() }
            .map { IntegrationId(it) },
      )
   }

   suspend fun findAll(): Result<List<Metric>> {
      return template.queryForList("SELECT * FROM `metric` ORDER BY `keyname`", mapper)
   }

   suspend fun insert(metric: Metric): Result<Int> {
      return template.update(
         """INSERT INTO `metric`
               (id, deployment_id, status, keyname, type, `query`, tags, integration_ids)
               VALUES (?,?,?,?,?,?,?,?)""",
         listOf(
            metric.id.value,
            metric.deploymentId.value,
            metric.status.name,
            metric.key.value,
            metric.type.name,
            metric.query,
            metric.tags.map { "${it.key}=${it.value}" }.joinToString(","),
            metric.integrationIds.joinToString(",") { it.value },
         )
      )
   }

   suspend fun update(metric: Metric): Result<Int> {
      return template.update(
         """UPDATE `metric` SET status=?, keyname=?, integration_ids=? WHERE id=?""",
         listOf(
            metric.status.name,
            metric.key.value,
            metric.integrationIds.joinToString(",") { it.value },
            metric.id.value,
         )
      )
   }

   suspend fun delete(metricId: MetricId): Result<Int> {
      return template.update(
         "DELETE FROM `metric` WHERE id=?",
         listOf(metricId.value)
      )
   }

   suspend fun getById(metricId: MetricId): Result<Metric?> {
      return template.query(
         "SELECT * FROM `metric` WHERE id=?",
         mapper,
         listOf(metricId.value)
      )
   }

   suspend fun setStatus(metricId: MetricId, status: MetricStatus): Result<Int> {
      return template.update(
         "UPDATE `metric` SET status=? WHERE id=?",
         listOf(status.name, metricId.value)
      )
   }
}