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 interface{}) (*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 interface{}) 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 interface{}, target interface{}) 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
}
