package agentidp

import (
	"context"
	"net/http"
	"strings"
	"time"
)

// AgentIdPClientConfig holds all configuration for AgentIdPClient.
type AgentIdPClientConfig struct {
	// BaseURL is the root URL of the AgentIdP server (e.g. "https://idp.example.com").
	BaseURL string
	// ClientID is the agent's OAuth 2.0 client ID.
	ClientID string
	// ClientSecret is the agent's OAuth 2.0 client secret.
	ClientSecret string
	// Scope is the space-separated list of OAuth 2.0 scopes to request.
	// Defaults to all four scopes when empty.
	Scope string
	// HTTPClient allows injecting a custom *http.Client (e.g. for testing).
	// When nil, a default client with a 30-second timeout is used.
	HTTPClient *http.Client
}

// AgentIdPClient is the top-level client for the SentryAgent.ai AgentIdP API.
// It composes all four service clients and manages token acquisition automatically.
//
// Usage:
//
//	client := agentidp.NewAgentIdPClient(agentidp.AgentIdPClientConfig{
//	    BaseURL:      "https://idp.example.com",
//	    ClientID:     "my-agent-id",
//	    ClientSecret: "sk_live_...",
//	})
//	agent, err := client.Agents.GetAgent(ctx, "uuid-1")
type AgentIdPClient struct {
	// Agents provides access to the Agent Registry endpoints.
	Agents *AgentRegistryClient
	// Credentials provides access to the Credential Management endpoints.
	Credentials *CredentialClient
	// Tokens provides access to the Token introspection and revocation endpoints.
	Tokens *TokenServiceClient
	// Audit provides access to the Audit Log endpoints.
	Audit *AuditClient

	tokenManager *TokenManager
}

// NewAgentIdPClient creates a new AgentIdPClient with the given configuration.
func NewAgentIdPClient(cfg AgentIdPClientConfig) *AgentIdPClient {
	baseURL := strings.TrimRight(cfg.BaseURL, "/")

	scope := cfg.Scope
	if scope == "" {
		scope = "agents:read agents:write tokens:read audit:read"
	}

	httpClient := cfg.HTTPClient
	if httpClient == nil {
		httpClient = &http.Client{Timeout: 30 * time.Second}
	}

	tm := NewTokenManager(baseURL, cfg.ClientID, cfg.ClientSecret, scope)

	getToken := func(ctx context.Context) (string, error) {
		return tm.GetToken(ctx)
	}

	return &AgentIdPClient{
		Agents:       newAgentRegistryClient(baseURL, getToken, httpClient),
		Credentials:  newCredentialClient(baseURL, getToken, httpClient),
		Tokens:       newTokenServiceClient(baseURL, getToken, httpClient),
		Audit:        newAuditClient(baseURL, getToken, httpClient),
		tokenManager: tm,
	}
}

// ClearTokenCache invalidates the cached access token.
// The next API call will fetch a fresh token from the server.
func (c *AgentIdPClient) ClearTokenCache() {
	c.tokenManager.ClearCache()
}
