package packages

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net/http"

	"github.com/paramah/ai_devs4/s01e03/internal/domain"
)

// APIClient implements domain.PackageClient
type APIClient struct {
	baseURL string
	apiKey  string
	client  *http.Client
	verbose bool
}

// NewAPIClient creates a new package API client
func NewAPIClient(baseURL, apiKey string, verbose bool) *APIClient {
	return &APIClient{
		baseURL: baseURL,
		apiKey:  apiKey,
		client:  &http.Client{},
		verbose: verbose,
	}
}

type checkRequest struct {
	APIKey    string `json:"apikey"`
	Action    string `json:"action"`
	PackageID string `json:"packageid"`
}

type checkResponse struct {
	Status   string `json:"status"`
	Location string `json:"location,omitempty"`
	Error    string `json:"error,omitempty"`
}

type redirectRequest struct {
	APIKey      string `json:"apikey"`
	Action      string `json:"action"`
	PackageID   string `json:"packageid"`
	Destination string `json:"destination"`
	Code        string `json:"code"`
}

type redirectResponse struct {
	Status       string `json:"status"`
	Message      string `json:"message,omitempty"`
	Confirmation string `json:"confirmation,omitempty"`
	Error        string `json:"error,omitempty"`
}

// Check checks the status of a package
func (c *APIClient) Check(ctx context.Context, packageID string) (*domain.PackageStatus, error) {
	reqBody := checkRequest{
		APIKey:    c.apiKey,
		Action:    "check",
		PackageID: packageID,
	}

	jsonData, err := json.Marshal(reqBody)
	if err != nil {
		return nil, fmt.Errorf("marshaling request: %w", err)
	}

	if c.verbose {
		var prettyJSON bytes.Buffer
		if err := json.Indent(&prettyJSON, jsonData, "", "  "); err == nil {
			log.Printf("\n========== PACKAGE API CHECK REQUEST ==========\nURL: %s\nBody:\n%s\n===============================================\n", c.baseURL, prettyJSON.String())
		}
	}

	req, err := http.NewRequestWithContext(ctx, http.MethodPost, c.baseURL, bytes.NewBuffer(jsonData))
	if err != nil {
		return nil, fmt.Errorf("creating request: %w", err)
	}

	req.Header.Set("Content-Type", "application/json")

	resp, err := c.client.Do(req)
	if err != nil {
		return nil, fmt.Errorf("sending request: %w", err)
	}
	defer resp.Body.Close()

	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, fmt.Errorf("reading response: %w", err)
	}

	if c.verbose {
		var prettyJSON bytes.Buffer
		if err := json.Indent(&prettyJSON, body, "", "  "); err == nil {
			log.Printf("\n========== PACKAGE API CHECK RESPONSE ==========\nStatus: %d\nBody:\n%s\n================================================\n", resp.StatusCode, prettyJSON.String())
		}
	}

	var apiResp checkResponse
	if err := json.Unmarshal(body, &apiResp); err != nil {
		return nil, fmt.Errorf("unmarshaling response: %w", err)
	}

	if apiResp.Error != "" {
		return nil, fmt.Errorf("API error: %s", apiResp.Error)
	}

	return &domain.PackageStatus{
		PackageID: packageID,
		Status:    apiResp.Status,
		Location:  apiResp.Location,
	}, nil
}

// Redirect redirects a package to a new destination and returns the confirmation message
func (c *APIClient) Redirect(ctx context.Context, packageID, destination, code string) (string, error) {
	reqBody := redirectRequest{
		APIKey:      c.apiKey,
		Action:      "redirect",
		PackageID:   packageID,
		Destination: destination,
		Code:        code,
	}

	jsonData, err := json.Marshal(reqBody)
	if err != nil {
		return "", fmt.Errorf("marshaling request: %w", err)
	}

	if c.verbose {
		var prettyJSON bytes.Buffer
		if err := json.Indent(&prettyJSON, jsonData, "", "  "); err == nil {
			log.Printf("\n========== PACKAGE API REDIRECT REQUEST ==========\nURL: %s\nBody:\n%s\n==================================================\n", c.baseURL, prettyJSON.String())
		}
	}

	req, err := http.NewRequestWithContext(ctx, http.MethodPost, c.baseURL, bytes.NewBuffer(jsonData))
	if err != nil {
		return "", fmt.Errorf("creating request: %w", err)
	}

	req.Header.Set("Content-Type", "application/json")

	resp, err := c.client.Do(req)
	if err != nil {
		return "", fmt.Errorf("sending request: %w", err)
	}
	defer resp.Body.Close()

	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return "", fmt.Errorf("reading response: %w", err)
	}

	if c.verbose {
		var prettyJSON bytes.Buffer
		if err := json.Indent(&prettyJSON, body, "", "  "); err == nil {
			log.Printf("\n========== PACKAGE API REDIRECT RESPONSE ==========\nStatus: %d\nBody:\n%s\n===================================================\n", resp.StatusCode, prettyJSON.String())
		}
	}

	var apiResp redirectResponse
	if err := json.Unmarshal(body, &apiResp); err != nil {
		return "", fmt.Errorf("unmarshaling response: %w", err)
	}

	if apiResp.Error != "" {
		return "", fmt.Errorf("API error: %s", apiResp.Error)
	}

	// Return the confirmation code
	if apiResp.Confirmation != "" {
		return apiResp.Confirmation, nil
	}

	// Fallback to message if confirmation is not present
	return apiResp.Message, nil
}
