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

import com.cameleer.server.app.AbstractPostgresIT;
import com.cameleer.server.app.TestSecurityHelper;
import com.cameleer.server.app.search.ClickHouseLogStore;
import com.fasterxml.jackson.databind.JsonNode;
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.beans.factory.annotation.Autowired;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;

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

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

class AlertSilenceControllerIT extends AbstractPostgresIT {

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

    @Autowired private TestRestTemplate restTemplate;
    @Autowired private ObjectMapper objectMapper;
    @Autowired private TestSecurityHelper securityHelper;

    private String operatorJwt;
    private String viewerJwt;
    private String envSlug;
    private UUID envId;

    @BeforeEach
    void setUp() {
        operatorJwt = securityHelper.operatorToken();
        viewerJwt   = securityHelper.viewerToken();
        seedUser("test-operator");
        seedUser("test-viewer");

        envSlug = "silence-env-" + UUID.randomUUID().toString().substring(0, 6);
        envId   = UUID.randomUUID();
        jdbcTemplate.update(
                "INSERT INTO environments (id, slug, display_name) VALUES (?, ?, ?) ON CONFLICT (id) DO NOTHING",
                envId, envSlug, envSlug);
    }

    @AfterEach
    void cleanUp() {
        jdbcTemplate.update("DELETE FROM alert_silences WHERE environment_id = ?", envId);
        jdbcTemplate.update("DELETE FROM environments WHERE id = ?", envId);
        jdbcTemplate.update("DELETE FROM users WHERE user_id IN ('test-operator','test-viewer')");
    }

    @Test
    void operatorCanCreate() throws Exception {
        ResponseEntity<String> resp = restTemplate.exchange(
                "/api/v1/environments/" + envSlug + "/alerts/silences",
                HttpMethod.POST,
                new HttpEntity<>(silenceBody(), securityHelper.authHeaders(operatorJwt)),
                String.class);

        assertThat(resp.getStatusCode()).isEqualTo(HttpStatus.CREATED);
        JsonNode body = objectMapper.readTree(resp.getBody());
        assertThat(body.path("id").asText()).isNotBlank();
        assertThat(body.path("reason").asText()).isEqualTo("planned-maintenance");
    }

    @Test
    void viewerCanList() {
        ResponseEntity<String> resp = restTemplate.exchange(
                "/api/v1/environments/" + envSlug + "/alerts/silences",
                HttpMethod.GET,
                new HttpEntity<>(securityHelper.authHeadersNoBody(viewerJwt)),
                String.class);
        assertThat(resp.getStatusCode()).isEqualTo(HttpStatus.OK);
    }

    @Test
    void viewerCannotCreate() {
        ResponseEntity<String> resp = restTemplate.exchange(
                "/api/v1/environments/" + envSlug + "/alerts/silences",
                HttpMethod.POST,
                new HttpEntity<>(silenceBody(), securityHelper.authHeaders(viewerJwt)),
                String.class);
        assertThat(resp.getStatusCode()).isEqualTo(HttpStatus.FORBIDDEN);
    }

    @Test
    void endsAtBeforeStartsAtReturns422() {
        Instant now = Instant.now();
        String body = """
                {"matcher":{},"reason":"bad","startsAt":"%s","endsAt":"%s"}
                """.formatted(now.plus(1, ChronoUnit.HOURS), now); // endsAt before startsAt

        ResponseEntity<String> resp = restTemplate.exchange(
                "/api/v1/environments/" + envSlug + "/alerts/silences",
                HttpMethod.POST,
                new HttpEntity<>(body, securityHelper.authHeaders(operatorJwt)),
                String.class);

        assertThat(resp.getStatusCode()).isEqualTo(HttpStatus.UNPROCESSABLE_ENTITY);
        assertThat(resp.getBody()).contains("endsAt must be after startsAt");
    }

    @Test
    void deleteRemovesSilence() throws Exception {
        ResponseEntity<String> create = restTemplate.exchange(
                "/api/v1/environments/" + envSlug + "/alerts/silences",
                HttpMethod.POST,
                new HttpEntity<>(silenceBody(), securityHelper.authHeaders(operatorJwt)),
                String.class);
        String id = objectMapper.readTree(create.getBody()).path("id").asText();

        ResponseEntity<String> del = restTemplate.exchange(
                "/api/v1/environments/" + envSlug + "/alerts/silences/" + id,
                HttpMethod.DELETE,
                new HttpEntity<>(securityHelper.authHeadersNoBody(operatorJwt)),
                String.class);
        assertThat(del.getStatusCode()).isEqualTo(HttpStatus.NO_CONTENT);
    }

    @Test
    void deleteEmitsAuditEvent() throws Exception {
        ResponseEntity<String> create = restTemplate.exchange(
                "/api/v1/environments/" + envSlug + "/alerts/silences",
                HttpMethod.POST,
                new HttpEntity<>(silenceBody(), securityHelper.authHeaders(operatorJwt)),
                String.class);
        String id = objectMapper.readTree(create.getBody()).path("id").asText();

        restTemplate.exchange(
                "/api/v1/environments/" + envSlug + "/alerts/silences/" + id,
                HttpMethod.DELETE,
                new HttpEntity<>(securityHelper.authHeadersNoBody(operatorJwt)),
                String.class);

        int count = jdbcTemplate.queryForObject(
                "SELECT COUNT(*) FROM audit_log WHERE action = 'ALERT_SILENCE_DELETE' AND target = ?",
                Integer.class, id);
        assertThat(count).isGreaterThanOrEqualTo(1);
    }

    // -------------------------------------------------------------------------
    // Helpers
    // -------------------------------------------------------------------------

    private void seedUser(String userId) {
        jdbcTemplate.update(
                "INSERT INTO users (user_id, provider, email, display_name) VALUES (?, 'test', ?, ?) ON CONFLICT (user_id) DO NOTHING",
                userId, userId + "@example.com", userId);
    }

    private static String silenceBody() {
        Instant start = Instant.now();
        Instant end   = start.plus(2, ChronoUnit.HOURS);
        return """
                {"matcher":{},"reason":"planned-maintenance","startsAt":"%s","endsAt":"%s"}
                """.formatted(start, end);
    }
}
