package agentidp

import (
	"context"
	"fmt"
	"net/http"
	"net/url"
	"strings"
)

// AgentRegistryClient provides methods for the Agent Registry API endpoints.
// All methods take a context.Context as first argument.
type AgentRegistryClient struct {
	baseURL    string
	getToken   func(ctx context.Context) (string, error)
	httpClient *http.Client
}

func newAgentRegistryClient(baseURL string, getToken func(ctx context.Context) (string, error), httpClient *http.Client) *AgentRegistryClient {
	return &AgentRegistryClient{
		baseURL:    strings.TrimRight(baseURL, "/"),
		getToken:   getToken,
		httpClient: httpClient,
	}
}

// RegisterAgent registers a new AI agent identity.
// POST /api/v1/agents → 201 Agent
func (c *AgentRegistryClient) RegisterAgent(ctx context.Context, req RegisterAgentRequest) (*Agent, error) {
	token, err := c.getToken(ctx)
	if err != nil {
		return nil, err
	}
	var agent Agent
	if err := doRequest(ctx, c.httpClient, http.MethodPost, c.baseURL+"/api/v1/agents", req, token, &agent); err != nil {
		return nil, err
	}
	return &agent, nil
}

// ListAgents returns a paginated list of registered agents.
// GET /api/v1/agents → 200 PaginatedAgents
func (c *AgentRegistryClient) ListAgents(ctx context.Context, params *ListAgentsParams) (*PaginatedAgents, error) {
	token, err := c.getToken(ctx)
	if err != nil {
		return nil, err
	}
	rawURL := c.baseURL + "/api/v1/agents"
	if params != nil {
		q := url.Values{}
		if params.Status != "" {
			q.Set("status", params.Status)
		}
		if params.AgentType != "" {
			q.Set("agentType", params.AgentType)
		}
		if params.DeploymentEnv != "" {
			q.Set("deploymentEnv", params.DeploymentEnv)
		}
		if params.Page > 0 {
			q.Set("page", fmt.Sprintf("%d", params.Page))
		}
		if params.Limit > 0 {
			q.Set("limit", fmt.Sprintf("%d", params.Limit))
		}
		if len(q) > 0 {
			rawURL += "?" + q.Encode()
		}
	}
	var result PaginatedAgents
	if err := doRequest(ctx, c.httpClient, http.MethodGet, rawURL, nil, token, &result); err != nil {
		return nil, err
	}
	return &result, nil
}

// GetAgent retrieves a single agent by ID.
// GET /api/v1/agents/:id → 200 Agent
func (c *AgentRegistryClient) GetAgent(ctx context.Context, agentID string) (*Agent, error) {
	token, err := c.getToken(ctx)
	if err != nil {
		return nil, err
	}
	var agent Agent
	if err := doRequest(ctx, c.httpClient, http.MethodGet, c.baseURL+"/api/v1/agents/"+agentID, nil, token, &agent); err != nil {
		return nil, err
	}
	return &agent, nil
}

// UpdateAgent partially updates an agent.
// PATCH /api/v1/agents/:id → 200 Agent
func (c *AgentRegistryClient) UpdateAgent(ctx context.Context, agentID string, req UpdateAgentRequest) (*Agent, error) {
	token, err := c.getToken(ctx)
	if err != nil {
		return nil, err
	}
	var agent Agent
	if err := doRequest(ctx, c.httpClient, http.MethodPatch, c.baseURL+"/api/v1/agents/"+agentID, req, token, &agent); err != nil {
		return nil, err
	}
	return &agent, nil
}

// DecommissionAgent permanently removes an agent.
// DELETE /api/v1/agents/:id → 204 No Content
func (c *AgentRegistryClient) DecommissionAgent(ctx context.Context, agentID string) error {
	token, err := c.getToken(ctx)
	if err != nil {
		return err
	}
	return doRequest(ctx, c.httpClient, http.MethodDelete, c.baseURL+"/api/v1/agents/"+agentID, nil, token, nil)
}
