package ai.sentryagent.idp.services;

import ai.sentryagent.idp.AgentIdPException;
import ai.sentryagent.idp.MockServer;
import ai.sentryagent.idp.models.IntrospectResponse;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.io.IOException;
import java.net.http.HttpClient;
import java.time.Duration;

import static org.junit.jupiter.api.Assertions.*;

class TokenClientTest {

    private MockServer srv;
    private TokenClient client;

    @BeforeEach
    void setUp() throws IOException {
        srv = new MockServer();
        HttpClient httpClient = HttpClient.newBuilder().connectTimeout(Duration.ofSeconds(5)).build();
        client = new TokenClient(srv.baseUrl(), () -> "test-token", httpClient);
    }

    @AfterEach
    void tearDown() { srv.stop(); }

    @Test
    void introspectToken_active() {
        srv.addHandler("/api/v1/token/introspect", 200,
            "{\"active\":true,\"sub\":\"uuid-1\",\"exp\":9999999999}");
        IntrospectResponse result = client.introspectToken("some-token");
        assertTrue(result.isActive());
        assertEquals("uuid-1", result.getSub());
    }

    @Test
    void introspectToken_inactive() {
        srv.addHandler("/api/v1/token/introspect", 200, "{\"active\":false}");
        IntrospectResponse result = client.introspectToken("expired-token");
        assertFalse(result.isActive());
        assertNull(result.getSub());
    }

    @Test
    void revokeToken_succeeds() {
        srv.addHandler("/api/v1/token/revoke", 200, "{}");
        assertDoesNotThrow(() -> client.revokeToken("some-token"));
    }

    @Test
    void introspectToken_error_throwsAgentIdPException() {
        srv.addHandler("/api/v1/token/introspect", 401,
            "{\"code\":\"UnauthorizedError\",\"message\":\"Invalid token.\"}");
        AgentIdPException ex = assertThrows(AgentIdPException.class,
            () -> client.introspectToken("bad-token"));
        assertEquals(401, ex.getHttpStatus());
        assertEquals("UnauthorizedError", ex.getCode());
    }

    @Test
    void revokeToken_error_throwsAgentIdPException() {
        srv.addHandler("/api/v1/token/revoke", 401,
            "{\"code\":\"UnauthorizedError\",\"message\":\"Invalid token.\"}");
        AgentIdPException ex = assertThrows(AgentIdPException.class,
            () -> client.revokeToken("bad-token"));
        assertEquals(401, ex.getHttpStatus());
    }

    @Test
    void introspectTokenAsync_active() throws Exception {
        srv.addHandler("/api/v1/token/introspect", 200,
            "{\"active\":true,\"sub\":\"uuid-1\",\"exp\":9999999999}");
        IntrospectResponse result = client.introspectTokenAsync("some-token").get();
        assertTrue(result.isActive());
    }

    @Test
    void revokeTokenAsync_succeeds() throws Exception {
        srv.addHandler("/api/v1/token/revoke", 200, "{}");
        assertDoesNotThrow(() -> client.revokeTokenAsync("some-token").get());
    }
}
