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 }