package ai.sentryagent.idp.services;

import ai.sentryagent.idp.AgentIdPException;
import ai.sentryagent.idp.MockServer;
import ai.sentryagent.idp.internal.HttpHelper;
import ai.sentryagent.idp.models.*;
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 CredentialClientTest {

    private MockServer srv;
    private CredentialClient client;

    private static final String CRED_JSON = """
        {"credentialId":"cred-1","clientId":"uuid-1","status":"active",
         "createdAt":"2026-01-01T00:00:00Z","expiresAt":null,"revokedAt":null}
        """;

    private static final String CRED_WITH_SECRET = """
        {"credentialId":"cred-1","clientId":"uuid-1","status":"active",
         "createdAt":"2026-01-01T00:00:00Z","expiresAt":null,"revokedAt":null,
         "clientSecret":"sk_live_abc"}
        """;

    private static final String PAGINATED_CREDS = """
        {"data":[%s],"total":1,"page":1,"limit":20}
        """.formatted(CRED_JSON.strip());

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

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

    @Test
    void generateCredential_returnsSecret() {
        srv.addHandler("/api/v1/agents/uuid-1/credentials", 201, CRED_WITH_SECRET);
        CredentialWithSecret cred = client.generateCredential("uuid-1");
        assertEquals("sk_live_abc", cred.getClientSecret());
        assertEquals("cred-1", cred.getCredentialId());
    }

    @Test
    void listCredentials_returnsPaginated() {
        srv.addHandler("/api/v1/agents/uuid-1/credentials", 200, PAGINATED_CREDS);
        PaginatedCredentials result = client.listCredentials("uuid-1", null, null);
        assertEquals(1, result.getTotal());
        assertEquals("cred-1", result.getData().get(0).getCredentialId());
    }

    @Test
    void rotateCredential_returnsNewSecret() {
        srv.addHandler("/api/v1/agents/uuid-1/credentials/cred-1/rotate", 200, CRED_WITH_SECRET);
        CredentialWithSecret cred = client.rotateCredential("uuid-1", "cred-1");
        assertEquals("sk_live_abc", cred.getClientSecret());
    }

    @Test
    void revokeCredential_returnsRevoked() {
        String revoked = """
            {"credentialId":"cred-1","clientId":"uuid-1","status":"revoked",
             "createdAt":"2026-01-01T00:00:00Z","expiresAt":null,
             "revokedAt":"2026-01-02T00:00:00Z"}
            """;
        srv.addHandler("/api/v1/agents/uuid-1/credentials/cred-1", 200, revoked);
        Credential cred = client.revokeCredential("uuid-1", "cred-1");
        assertEquals("revoked", cred.getStatus());
    }

    @Test
    void generateCredential_error_throwsAgentIdPException() {
        srv.addHandler("/api/v1/agents/bad/credentials", 404,
            "{\"code\":\"AgentNotFoundError\",\"message\":\"Not found.\"}");
        AgentIdPException ex = assertThrows(AgentIdPException.class,
            () -> client.generateCredential("bad"));
        assertEquals(404, ex.getHttpStatus());
    }

    @Test
    void generateCredentialAsync_returnsCompletableFuture() throws Exception {
        srv.addHandler("/api/v1/agents/uuid-1/credentials", 201, CRED_WITH_SECRET);
        CredentialWithSecret cred = client.generateCredentialAsync("uuid-1").get();
        assertEquals("sk_live_abc", cred.getClientSecret());
    }

    @Test
    void rotateCredentialAsync_returnsCompletableFuture() throws Exception {
        srv.addHandler("/api/v1/agents/uuid-1/credentials/cred-1/rotate", 200, CRED_WITH_SECRET);
        CredentialWithSecret cred = client.rotateCredentialAsync("uuid-1", "cred-1").get();
        assertEquals("sk_live_abc", cred.getClientSecret());
    }

    @Test
    void revokeCredentialAsync_returnsCompletableFuture() throws Exception {
        String revoked = """
            {"credentialId":"cred-1","clientId":"uuid-1","status":"revoked",
             "createdAt":"2026-01-01T00:00:00Z","expiresAt":null,
             "revokedAt":"2026-01-02T00:00:00Z"}
            """;
        srv.addHandler("/api/v1/agents/uuid-1/credentials/cred-1", 200, revoked);
        Credential cred = client.revokeCredentialAsync("uuid-1", "cred-1").get();
        assertEquals("revoked", cred.getStatus());
    }
}
