package service

import (
	"context"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"strings"
	"time"

	"github.com/korap/korap-mcp/auth"
	"github.com/korap/korap-mcp/config"
)

// Client represents a KorAP API client
type Client struct {
	baseURL     string
	httpClient  *http.Client
	oauthClient *auth.OAuthClient
}

// ClientOptions configures the KorAP client
type ClientOptions struct {
	BaseURL     string
	Timeout     time.Duration
	OAuthConfig *config.OAuthConfig
}

// NewClient creates a new KorAP API client
func NewClient(opts ClientOptions) (*Client, error) {
	if opts.BaseURL == "" {
		return nil, fmt.Errorf("base URL is required")
	}

	// Ensure base URL ends with /
	baseURL := strings.TrimSuffix(opts.BaseURL, "/") + "/"

	// Set default timeout if not specified
	timeout := opts.Timeout
	if timeout == 0 {
		timeout = 30 * time.Second
	}

	client := &Client{
		baseURL: baseURL,
		httpClient: &http.Client{
			Timeout: timeout,
		},
	}

	// Initialize OAuth client if configuration is provided
	if opts.OAuthConfig != nil && opts.OAuthConfig.Enabled {
		oauthClient, err := auth.NewOAuthClient(opts.OAuthConfig)
		if err != nil {
			return nil, fmt.Errorf("failed to create OAuth client: %w", err)
		}
		client.oauthClient = oauthClient
	}

	return client, nil
}

// SetOAuthClient sets the OAuth client for authentication
func (c *Client) SetOAuthClient(oauthClient *auth.OAuthClient) {
	c.oauthClient = oauthClient
}

// IsAuthenticated returns true if the client has valid authentication
func (c *Client) IsAuthenticated() bool {
	return c.oauthClient != nil && c.oauthClient.IsAuthenticated()
}

// AuthenticateWithClientCredentials performs client credentials OAuth flow
func (c *Client) AuthenticateWithClientCredentials(ctx context.Context) error {
	if c.oauthClient == nil {
		return fmt.Errorf("OAuth client not configured")
	}

	return c.oauthClient.ClientCredentialsFlow(ctx)
}

// buildURL constructs a full URL from the base URL and endpoint
func (c *Client) buildURL(endpoint string) (string, error) {
	endpoint = strings.TrimPrefix(endpoint, "/")
	if endpoint == "" {
		return c.baseURL, nil
	}
	fullURL, err := url.JoinPath(c.baseURL, endpoint)
	if err != nil {
		return "", fmt.Errorf("failed to build URL: %w", err)
	}
	return fullURL, nil
}

// doRequest performs an HTTP request with optional authentication
func (c *Client) doRequest(ctx context.Context, method, endpoint string, body io.Reader) (*http.Response, error) {
	fullURL, err := c.buildURL(endpoint)
	if err != nil {
		return nil, err
	}

	req, err := http.NewRequestWithContext(ctx, method, fullURL, body)
	if err != nil {
		return nil, fmt.Errorf("failed to create request: %w", err)
	}

	// Set common headers
	req.Header.Set("Accept", "application/json")
	if body != nil {
		req.Header.Set("Content-Type", "application/json")
	}

	// Add authentication if available
	if c.oauthClient != nil && c.oauthClient.IsAuthenticated() {
		if err := c.oauthClient.AddAuthHeader(req); err != nil {
			return nil, fmt.Errorf("failed to add auth header: %w", err)
		}
	}

	// Use OAuth HTTP client if available, otherwise use default client
	httpClient := c.httpClient
	if c.oauthClient != nil {
		httpClient = c.oauthClient.GetHTTPClient()
	}

	resp, err := httpClient.Do(req)
	if err != nil {
		return nil, fmt.Errorf("request failed: %w", err)
	}

	return resp, nil
}

// Get performs a GET request to the specified endpoint
func (c *Client) Get(ctx context.Context, endpoint string) (*http.Response, error) {
	return c.doRequest(ctx, http.MethodGet, endpoint, nil)
}

// Post performs a POST request to the specified endpoint with JSON body
func (c *Client) Post(ctx context.Context, endpoint string, body any) (*http.Response, error) {
	var bodyReader io.Reader
	if body != nil {
		jsonBody, err := json.Marshal(body)
		if err != nil {
			return nil, fmt.Errorf("failed to marshal request body: %w", err)
		}
		bodyReader = strings.NewReader(string(jsonBody))
	}

	return c.doRequest(ctx, http.MethodPost, endpoint, bodyReader)
}

// GetJSON performs a GET request and unmarshals the JSON response
func (c *Client) GetJSON(ctx context.Context, endpoint string, target any) error {
	resp, err := c.Get(ctx, endpoint)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	if resp.StatusCode < 200 || resp.StatusCode >= 300 {
		return c.handleErrorResponse(resp)
	}

	if err := json.NewDecoder(resp.Body).Decode(target); err != nil {
		return fmt.Errorf("failed to decode JSON response: %w", err)
	}

	return nil
}

// PostJSON performs a POST request and unmarshals the JSON response
func (c *Client) PostJSON(ctx context.Context, endpoint string, body any, target any) error {
	resp, err := c.Post(ctx, endpoint, body)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	if resp.StatusCode < 200 || resp.StatusCode >= 300 {
		return c.handleErrorResponse(resp)
	}

	if target != nil {
		if err := json.NewDecoder(resp.Body).Decode(target); err != nil {
			return fmt.Errorf("failed to decode JSON response: %w", err)
		}
	}

	return nil
}

// handleErrorResponse processes error responses from the KorAP API
func (c *Client) handleErrorResponse(resp *http.Response) error {
	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return fmt.Errorf("HTTP %d: failed to read error response", resp.StatusCode)
	}

	// Try to parse as KorAP error response
	var errorResp ErrorResponse
	if json.Unmarshal(body, &errorResp) == nil && errorResp.Error != "" {
		return &APIError{
			StatusCode: resp.StatusCode,
			Message:    errorResp.Error,
			Details:    errorResp.ErrorDescription,
		}
	}

	// Fallback to generic error
	return &APIError{
		StatusCode: resp.StatusCode,
		Message:    fmt.Sprintf("HTTP %d", resp.StatusCode),
		Details:    string(body),
	}
}

// GetBaseURL returns the base URL of the KorAP instance
func (c *Client) GetBaseURL() string {
	return c.baseURL
}

// Ping checks if the KorAP server is reachable
func (c *Client) Ping(ctx context.Context) error {
	resp, err := c.Get(ctx, "")
	if err != nil {
		return fmt.Errorf("failed to ping KorAP server: %w", err)
	}
	defer resp.Body.Close()

	if resp.StatusCode >= 500 {
		return fmt.Errorf("KorAP server error: HTTP %d", resp.StatusCode)
	}

	return nil
}
