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

import com.cameleer.server.app.AbstractPostgresIT;
import com.cameleer.server.app.search.ClickHouseLogStore;
import com.cameleer.server.core.alerting.AlertSilence;
import com.cameleer.server.core.alerting.SilenceMatcher;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.mock.mockito.MockBean;

import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.UUID;

import static org.assertj.core.api.Assertions.assertThat;

class PostgresAlertSilenceRepositoryIT extends AbstractPostgresIT {

    @MockBean(name = "clickHouseLogStore")    ClickHouseLogStore    clickHouseLogStore;

    private PostgresAlertSilenceRepository repo;
    private UUID envId;

    @BeforeEach
    void setup() {
        repo = new PostgresAlertSilenceRepository(jdbcTemplate, new ObjectMapper());
        envId = UUID.randomUUID();
        jdbcTemplate.update(
            "INSERT INTO environments (id, slug, display_name) VALUES (?, ?, ?)",
            envId, "test-env-" + UUID.randomUUID(), "Test Env");
        jdbcTemplate.update(
            "INSERT INTO users (user_id, provider, email) VALUES ('sys-user', 'local', 'sys@example.com') ON CONFLICT (user_id) DO NOTHING");
    }

    @AfterEach
    void cleanup() {
        jdbcTemplate.update("DELETE FROM alert_silences WHERE environment_id = ?", envId);
        jdbcTemplate.update("DELETE FROM environments WHERE id = ?", envId);
    }

    @Test
    void saveAndFindByIdRoundtrip() {
        var silence = newSilence(Instant.now().minusSeconds(60), Instant.now().plusSeconds(3600));
        repo.save(silence);

        var found = repo.findById(silence.id()).orElseThrow();
        assertThat(found.id()).isEqualTo(silence.id());
        assertThat(found.environmentId()).isEqualTo(envId);
        assertThat(found.reason()).isEqualTo("test reason");
        assertThat(found.matcher()).isNotNull();
        assertThat(found.matcher().isWildcard()).isTrue();
    }

    @Test
    void listActive_returnsOnlyCurrentSilences() {
        Instant now = Instant.now();
        var active = newSilence(now.minusSeconds(60), now.plusSeconds(3600));
        var future = newSilence(now.plusSeconds(60), now.plusSeconds(7200));
        var past   = newSilence(now.minusSeconds(7200), now.minusSeconds(60));

        repo.save(active);
        repo.save(future);
        repo.save(past);

        var result = repo.listActive(envId, now);
        assertThat(result).extracting(AlertSilence::id)
            .containsExactly(active.id())
            .doesNotContain(future.id(), past.id());
    }

    @Test
    void delete_removesRow() {
        var silence = newSilence(Instant.now().minusSeconds(60), Instant.now().plusSeconds(3600));
        repo.save(silence);
        assertThat(repo.findById(silence.id())).isPresent();

        repo.delete(silence.id());

        assertThat(repo.findById(silence.id())).isEmpty();
    }

    @Test
    void listByEnvironment_returnsAll() {
        repo.save(newSilence(Instant.now().minusSeconds(60), Instant.now().plusSeconds(3600)));
        repo.save(newSilence(Instant.now().minusSeconds(30), Instant.now().plusSeconds(1800)));

        var list = repo.listByEnvironment(envId);
        assertThat(list).hasSize(2);
    }

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

    private AlertSilence newSilence(Instant startsAt, Instant endsAt) {
        return new AlertSilence(
            UUID.randomUUID(), envId,
            new SilenceMatcher(null, null, null, null, null),
            "test reason", startsAt, endsAt, "sys-user", Instant.now());
    }
}
