package io.cameleer.server.app.controller;

import io.cameleer.server.app.AbstractPostgresIT;
import io.cameleer.server.app.dto.AuthCapabilitiesResponse;
import io.cameleer.server.core.security.OidcConfig;
import io.cameleer.server.core.security.OidcConfigRepository;
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 java.util.List;
import java.util.Optional;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.when;

/**
 * Integration tests for {@link io.cameleer.server.app.security.AuthCapabilitiesController}.
 * Mocks {@link OidcConfigRepository} so each test controls the OIDC state it observes.
 */
class AuthCapabilitiesControllerIT extends AbstractPostgresIT {

    @Autowired private TestRestTemplate restTemplate;
    @MockBean private OidcConfigRepository oidcConfigRepository;

    @BeforeEach
    void resetMock() {
        when(oidcConfigRepository.find()).thenReturn(Optional.empty());
    }

    @Test
    void noOidcConfig_returnsLocalOnlyCaps() {
        var resp = restTemplate.getForEntity("/api/v1/auth/capabilities", AuthCapabilitiesResponse.class);

        assertThat(resp.getStatusCode().value()).isEqualTo(200);
        assertThat(resp.getBody()).isNotNull();
        assertThat(resp.getBody().oidc().enabled()).isFalse();
        assertThat(resp.getBody().oidc().providerName()).isEqualTo("");
        assertThat(resp.getBody().oidc().primary()).isFalse();
        assertThat(resp.getBody().localAccounts().enabled()).isTrue();
        assertThat(resp.getBody().localAccounts().adminRecoveryOnly()).isFalse();
    }

    @Test
    void oidcDisabledRow_behavesLikeAbsent() {
        OidcConfig disabled = new OidcConfig(false, "https://auth.logto.example/", "client-id", "secret",
                "roles", List.of("VIEWER"), true, "name", "sub", "", List.of());
        when(oidcConfigRepository.find()).thenReturn(Optional.of(disabled));

        var resp = restTemplate.getForEntity("/api/v1/auth/capabilities", AuthCapabilitiesResponse.class);

        assertThat(resp.getStatusCode().value()).isEqualTo(200);
        assertThat(resp.getBody().oidc().enabled()).isFalse();
        assertThat(resp.getBody().oidc().providerName()).isEqualTo("");
        assertThat(resp.getBody().oidc().primary()).isFalse();
        assertThat(resp.getBody().localAccounts().adminRecoveryOnly()).isFalse();
    }

    @Test
    void oidcEnabledLogto_returnsOidcPrimaryWithProviderName() {
        OidcConfig enabled = new OidcConfig(true, "https://auth.logto.example/", "client-id", "secret",
                "roles", List.of("VIEWER"), true, "name", "sub", "", List.of());
        when(oidcConfigRepository.find()).thenReturn(Optional.of(enabled));

        var resp = restTemplate.getForEntity("/api/v1/auth/capabilities", AuthCapabilitiesResponse.class);

        assertThat(resp.getStatusCode().value()).isEqualTo(200);
        assertThat(resp.getBody().oidc().enabled()).isTrue();
        assertThat(resp.getBody().oidc().providerName()).isEqualTo("Logto");
        assertThat(resp.getBody().oidc().primary()).isTrue();
        assertThat(resp.getBody().localAccounts().enabled()).isTrue();
        assertThat(resp.getBody().localAccounts().adminRecoveryOnly()).isTrue();
    }

    @Test
    void oidcEnabledUnknownProvider_returnsGenericProviderName() {
        OidcConfig enabled = new OidcConfig(true, "https://idp.example.com/", "client-id", "secret",
                "roles", List.of("VIEWER"), true, "name", "sub", "", List.of());
        when(oidcConfigRepository.find()).thenReturn(Optional.of(enabled));

        var resp = restTemplate.getForEntity("/api/v1/auth/capabilities", AuthCapabilitiesResponse.class);

        assertThat(resp.getStatusCode().value()).isEqualTo(200);
        assertThat(resp.getBody().oidc().providerName()).isEqualTo("Single Sign-On");
        assertThat(resp.getBody().oidc().primary()).isTrue();
        assertThat(resp.getBody().localAccounts().adminRecoveryOnly()).isTrue();
    }

    @Test
    void endpointIsUnauthenticated() {
        var resp = restTemplate.getForEntity("/api/v1/auth/capabilities", String.class);
        assertThat(resp.getStatusCode().value()).isEqualTo(200);
    }
}
