package agentidp

import (
	"bytes"
	"context"
	"encoding/json"
	"io"
	"net/http"
	"net/url"
	"strings"
)

// TokenServiceClient provides token introspection and revocation.
// Token acquisition is handled separately by TokenManager.
type TokenServiceClient struct {
	baseURL    string
	getToken   func(ctx context.Context) (string, error)
	httpClient *http.Client
}

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

// IntrospectToken introspects an access token per RFC 7662.
// POST /api/v1/token/introspect (form-encoded) → 200 IntrospectResponse
func (c *TokenServiceClient) IntrospectToken(ctx context.Context, accessToken string) (*IntrospectResponse, error) {
	bearerToken, err := c.getToken(ctx)
	if err != nil {
		return nil, err
	}

	form := url.Values{}
	form.Set("token", accessToken)

	req, err := http.NewRequestWithContext(ctx, http.MethodPost, c.baseURL+"/api/v1/token/introspect", bytes.NewBufferString(form.Encode()))
	if err != nil {
		return nil, &AgentIdPError{Code: "REQUEST_BUILD_ERROR", Message: "failed to build introspect request: " + err.Error()}
	}
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	req.Header.Set("Accept", "application/json")
	req.Header.Set("Authorization", "Bearer "+bearerToken)

	resp, err := c.httpClient.Do(req)
	if err != nil {
		return nil, newNetworkError(err)
	}
	defer resp.Body.Close() //nolint:errcheck

	respBody, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, newNetworkError(err)
	}

	if resp.StatusCode < 200 || resp.StatusCode >= 300 {
		return nil, parseAPIError(respBody, resp.StatusCode)
	}

	var result IntrospectResponse
	if err := json.Unmarshal(respBody, &result); err != nil {
		return nil, &AgentIdPError{Code: "PARSE_ERROR", Message: "failed to parse introspect response: " + err.Error(), HTTPStatus: resp.StatusCode}
	}
	return &result, nil
}

// RevokeToken revokes an access token.
// POST /api/v1/token/revoke (form-encoded) → 200
func (c *TokenServiceClient) RevokeToken(ctx context.Context, accessToken string) error {
	bearerToken, err := c.getToken(ctx)
	if err != nil {
		return err
	}

	form := url.Values{}
	form.Set("token", accessToken)

	req, err := http.NewRequestWithContext(ctx, http.MethodPost, c.baseURL+"/api/v1/token/revoke", bytes.NewBufferString(form.Encode()))
	if err != nil {
		return &AgentIdPError{Code: "REQUEST_BUILD_ERROR", Message: "failed to build revoke request: " + err.Error()}
	}
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	req.Header.Set("Authorization", "Bearer "+bearerToken)

	resp, err := c.httpClient.Do(req)
	if err != nil {
		return newNetworkError(err)
	}
	defer resp.Body.Close() //nolint:errcheck

	respBody, err := io.ReadAll(resp.Body)
	if err != nil {
		return newNetworkError(err)
	}

	if resp.StatusCode < 200 || resp.StatusCode >= 300 {
		return parseAPIError(respBody, resp.StatusCode)
	}
	return nil
}
