package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"os"
)

// Client wraps the HTTP client with authentication support
type Client struct {
	baseURL  string
	authKey  string
	username string
	password string
	client   *http.Client
}

// NewClient creates a new authenticated HTTP client
func NewClient(cfg *CLIConfig) *Client {
	return &Client{
		baseURL:  cfg.ServerURL,
		authKey:  cfg.AuthKey,
		username: cfg.Username,
		password: cfg.Password,
		client:   &http.Client{},
	}
}

// addAuth adds authentication headers to the request
func (c *Client) addAuth(req *http.Request) {
	// Priority 1: API Key (as Bearer token or x-api-key header)
	if c.authKey != "" {
		req.Header.Set("Authorization", "Bearer "+c.authKey)
		req.Header.Set("x-api-key", c.authKey)
		return
	}

	// Priority 2: Basic Auth (username/password)
	if c.username != "" && c.password != "" {
		req.SetBasicAuth(c.username, c.password)
	}
}

// Get performs an authenticated GET request
func (c *Client) Get(path string) (*http.Response, error) {
	req, err := http.NewRequest("GET", c.baseURL+path, nil)
	if err != nil {
		return nil, err
	}

	c.addAuth(req)
	resp, err := c.client.Do(req)
	if err != nil {
		return nil, err
	}

	// Check for HTTP error status codes
	if resp.StatusCode >= 400 {
		defer resp.Body.Close()
		body, _ := io.ReadAll(resp.Body)
		return nil, fmt.Errorf("HTTP %d: %s", resp.StatusCode, string(body))
	}

	return resp, nil
}

// Post performs an authenticated POST request with JSON data
func (c *Client) Post(path string, data interface{}) (*http.Response, error) {
	jsonData, err := json.Marshal(data)
	if err != nil {
		return nil, err
	}

	req, err := http.NewRequest("POST", c.baseURL+path, bytes.NewReader(jsonData))
	if err != nil {
		return nil, err
	}

	req.Header.Set("Content-Type", "application/json")
	c.addAuth(req)
	resp, err := c.client.Do(req)
	if err != nil {
		return nil, err
	}

	// Check for HTTP error status codes
	if resp.StatusCode >= 400 {
		defer resp.Body.Close()
		body, _ := io.ReadAll(resp.Body)
		return nil, fmt.Errorf("HTTP %d: %s", resp.StatusCode, string(body))
	}

	return resp, nil
}

// decodeJSON decodes JSON response into target
func decodeJSON(resp *http.Response, target interface{}) error {
	defer resp.Body.Close()
	return json.NewDecoder(resp.Body).Decode(target)
}

// serverAvailable checks if the server is reachable via the health endpoint.
func serverAvailable(client *Client) bool {
	resp, err := client.client.Get(client.baseURL + "/health")
	if err != nil {
		return false
	}
	resp.Body.Close()
	return resp.StatusCode < 500
}

// checkError prints error and exits if error is not nil
func checkError(err error) {
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error: %v\n", err)
		os.Exit(1)
	}
}
