package org.raddatz.familienarchiv.config;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import org.raddatz.familienarchiv.PostgresContainerConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.data.jpa.test.autoconfigure.DataJpaTest;
import org.springframework.boot.jdbc.test.autoconfigure.AutoConfigureTestDatabase;
import org.springframework.context.annotation.Import;
import org.springframework.jdbc.core.JdbcTemplate;

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

// GRAFANA_DB_PASSWORD is supplied via the global test default in
// src/test/resources/application.properties — FlywayConfig fails closed
// when it is unset, so all tests that load the migration path need it.
@DataJpaTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
@Import({PostgresContainerConfig.class, FlywayConfig.class})
class GrafanaReaderRoleIntegrationTest {

    @Autowired JdbcTemplate jdbc;

    // --- positive grants (SELECT on the three explicitly granted tables) ---

    @Test
    void grafana_reader_has_select_on_audit_log() {
        assertThat(hasPrivilege("audit_log", "SELECT")).isTrue();
    }

    @Test
    void grafana_reader_has_select_on_documents() {
        assertThat(hasPrivilege("documents", "SELECT")).isTrue();
    }

    @Test
    void grafana_reader_has_select_on_transcription_blocks() {
        assertThat(hasPrivilege("transcription_blocks", "SELECT")).isTrue();
    }

    // --- write-deny on the granted tables: SELECT-only means SELECT-only.
    // A future migration that GRANTs INSERT/UPDATE/DELETE on any of these
    // would fail these tests, even though the original positive grants still
    // pass. Locks the boundary in both directions.

    @Test
    void grafana_reader_has_no_INSERT_on_documents() {
        assertThat(hasPrivilege("documents", "INSERT")).isFalse();
    }

    @Test
    void grafana_reader_has_no_UPDATE_on_audit_log() {
        assertThat(hasPrivilege("audit_log", "UPDATE")).isFalse();
    }

    @Test
    void grafana_reader_has_no_DELETE_on_transcription_blocks() {
        assertThat(hasPrivilege("transcription_blocks", "DELETE")).isFalse();
    }

    // --- negative grants: PII / sensitive tables MUST NOT be readable.
    // The parameterized form catches the "someone widened the grant to
    // ALL TABLES IN SCHEMA public" footgun — three specific positive grants
    // would still pass while this sweep turns red.

    @ParameterizedTest
    @ValueSource(strings = {
            "app_users",
            "user_groups",
            "persons",
            "notifications",
            "document_comments",
            "document_annotations",
            "geschichten"
    })
    void grafana_reader_has_no_SELECT_on_protected_table(String table) {
        assertThat(hasPrivilege(table, "SELECT")).isFalse();
    }

    private boolean hasPrivilege(String table, String privilege) {
        Boolean result = jdbc.queryForObject(
                "SELECT has_table_privilege('grafana_reader', ?, ?)",
                Boolean.class,
                table,
                privilege);
        return Boolean.TRUE.equals(result);
    }
}
