package com.cameleer.server.app.alerting.storage;

import com.cameleer.server.core.alerting.AlertSilence;
import com.cameleer.server.core.alerting.AlertSilenceRepository;
import com.cameleer.server.core.alerting.AlertSeverity;
import com.cameleer.server.core.alerting.SilenceMatcher;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;

import java.sql.Timestamp;
import java.time.Instant;
import java.util.List;
import java.util.Optional;
import java.util.UUID;

public class PostgresAlertSilenceRepository implements AlertSilenceRepository {

    private final JdbcTemplate jdbc;
    private final ObjectMapper om;

    public PostgresAlertSilenceRepository(JdbcTemplate jdbc, ObjectMapper om) {
        this.jdbc = jdbc;
        this.om = om;
    }

    @Override
    public AlertSilence save(AlertSilence s) {
        jdbc.update("""
            INSERT INTO alert_silences (id, environment_id, matcher, reason, starts_at, ends_at, created_by, created_at)
            VALUES (?, ?, ?::jsonb, ?, ?, ?, ?, ?)
            ON CONFLICT (id) DO UPDATE SET
                matcher    = EXCLUDED.matcher,
                reason     = EXCLUDED.reason,
                starts_at  = EXCLUDED.starts_at,
                ends_at    = EXCLUDED.ends_at
            """,
            s.id(), s.environmentId(), writeJson(s.matcher()),
            s.reason(),
            Timestamp.from(s.startsAt()), Timestamp.from(s.endsAt()),
            s.createdBy(), Timestamp.from(s.createdAt()));
        return s;
    }

    @Override
    public Optional<AlertSilence> findById(UUID id) {
        var list = jdbc.query("SELECT * FROM alert_silences WHERE id = ?", rowMapper(), id);
        return list.isEmpty() ? Optional.empty() : Optional.of(list.get(0));
    }

    @Override
    public List<AlertSilence> listActive(UUID environmentId, Instant when) {
        Timestamp t = Timestamp.from(when);
        return jdbc.query("""
            SELECT * FROM alert_silences
             WHERE environment_id = ?
               AND starts_at <= ? AND ends_at >= ?
             ORDER BY starts_at
            """, rowMapper(), environmentId, t, t);
    }

    @Override
    public List<AlertSilence> listByEnvironment(UUID environmentId) {
        return jdbc.query("""
            SELECT * FROM alert_silences
             WHERE environment_id = ?
             ORDER BY starts_at DESC
            """, rowMapper(), environmentId);
    }

    @Override
    public void delete(UUID id) {
        jdbc.update("DELETE FROM alert_silences WHERE id = ?", id);
    }

    // -------------------------------------------------------------------------

    private RowMapper<AlertSilence> rowMapper() {
        return (rs, i) -> {
            try {
                SilenceMatcher matcher = om.readValue(rs.getString("matcher"), SilenceMatcher.class);
                return new AlertSilence(
                    (UUID) rs.getObject("id"),
                    (UUID) rs.getObject("environment_id"),
                    matcher,
                    rs.getString("reason"),
                    rs.getTimestamp("starts_at").toInstant(),
                    rs.getTimestamp("ends_at").toInstant(),
                    rs.getString("created_by"),
                    rs.getTimestamp("created_at").toInstant());
            } catch (Exception e) {
                throw new IllegalStateException("Failed to map alert_silences row", e);
            }
        };
    }

    private String writeJson(Object o) {
        try { return om.writeValueAsString(o); }
        catch (Exception e) { throw new IllegalStateException("Failed to serialize JSON", e); }
    }
}
