package pexels import ( "context" "encoding/json" "fmt" "net/http" "net/url" "time" ) const ( pexelsSearchURL = "https://api.pexels.com/v1/search" defaultPlaceholder = "https://images.pexels.com/photos/1640777/pexels-photo-1640777.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750" ) // Client is an HTTP client for the Pexels Photos API. type Client struct { apiKey string httpClient *http.Client } // NewClient creates a new Pexels client. func NewClient(apiKey string) *Client { return &Client{ apiKey: apiKey, httpClient: &http.Client{ Timeout: 10 * time.Second, }, } } // SearchPhoto searches for a landscape photo matching query. // Returns a default placeholder URL if no photo is found or on error. func (c *Client) SearchPhoto(ctx context.Context, query string) (string, error) { params := url.Values{} params.Set("query", query) params.Set("per_page", "1") params.Set("orientation", "landscape") req, err := http.NewRequestWithContext(ctx, http.MethodGet, pexelsSearchURL+"?"+params.Encode(), nil) if err != nil { return defaultPlaceholder, fmt.Errorf("create request: %w", err) } req.Header.Set("Authorization", c.apiKey) resp, err := c.httpClient.Do(req) if err != nil { return defaultPlaceholder, fmt.Errorf("send request: %w", err) } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { return defaultPlaceholder, fmt.Errorf("pexels API error: status %d", resp.StatusCode) } var result struct { Photos []struct { Src struct { Medium string `json:"medium"` } `json:"src"` } `json:"photos"` } if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { return defaultPlaceholder, fmt.Errorf("decode response: %w", err) } if len(result.Photos) == 0 || result.Photos[0].Src.Medium == "" { return defaultPlaceholder, nil } return result.Photos[0].Src.Medium, nil }