package content import ( "encoding/json" "fmt" "io" "net/http" "net/url" "strings" "time" "github.com/insertr/insertr/internal/engine" ) // HTTPClient implements ContentClient for HTTP API access type HTTPClient struct { BaseURL string APIKey string HTTPClient *http.Client } // NewHTTPClient creates a new HTTP content client func NewHTTPClient(baseURL, apiKey string) *HTTPClient { return &HTTPClient{ BaseURL: strings.TrimSuffix(baseURL, "/"), APIKey: apiKey, HTTPClient: &http.Client{ Timeout: 30 * time.Second, }, } } // GetContent fetches a single content item by ID func (c *HTTPClient) GetContent(siteID, contentID string) (*engine.ContentItem, error) { url := fmt.Sprintf("%s/api/content/%s?site_id=%s", c.BaseURL, contentID, siteID) req, err := http.NewRequest("GET", url, nil) if err != nil { return nil, fmt.Errorf("creating request: %w", err) } if c.APIKey != "" { req.Header.Set("Authorization", "Bearer "+c.APIKey) } resp, err := c.HTTPClient.Do(req) if err != nil { return nil, fmt.Errorf("making request: %w", err) } defer resp.Body.Close() if resp.StatusCode == 404 { return nil, nil // Content not found, return nil without error } if resp.StatusCode != 200 { return nil, fmt.Errorf("API error: %s", resp.Status) } body, err := io.ReadAll(resp.Body) if err != nil { return nil, fmt.Errorf("reading response: %w", err) } var item engine.ContentItem if err := json.Unmarshal(body, &item); err != nil { return nil, fmt.Errorf("parsing response: %w", err) } return &item, nil } // GetBulkContent fetches multiple content items by IDs func (c *HTTPClient) GetBulkContent(siteID string, contentIDs []string) (map[string]engine.ContentItem, error) { if len(contentIDs) == 0 { return make(map[string]engine.ContentItem), nil } // Build query parameters params := url.Values{} params.Set("site_id", siteID) for _, id := range contentIDs { params.Add("ids", id) } url := fmt.Sprintf("%s/api/content/bulk?%s", c.BaseURL, params.Encode()) req, err := http.NewRequest("GET", url, nil) if err != nil { return nil, fmt.Errorf("creating request: %w", err) } if c.APIKey != "" { req.Header.Set("Authorization", "Bearer "+c.APIKey) } resp, err := c.HTTPClient.Do(req) if err != nil { return nil, fmt.Errorf("making request: %w", err) } defer resp.Body.Close() if resp.StatusCode != 200 { return nil, fmt.Errorf("API error: %s", resp.Status) } body, err := io.ReadAll(resp.Body) if err != nil { return nil, fmt.Errorf("reading response: %w", err) } var response engine.ContentResponse if err := json.Unmarshal(body, &response); err != nil { return nil, fmt.Errorf("parsing response: %w", err) } // Convert slice to map for easy lookup result := make(map[string]engine.ContentItem) for _, item := range response.Content { result[item.ID] = item } return result, nil } // GetAllContent fetches all content for a site func (c *HTTPClient) GetAllContent(siteID string) (map[string]engine.ContentItem, error) { url := fmt.Sprintf("%s/api/content?site_id=%s", c.BaseURL, siteID) req, err := http.NewRequest("GET", url, nil) if err != nil { return nil, fmt.Errorf("creating request: %w", err) } if c.APIKey != "" { req.Header.Set("Authorization", "Bearer "+c.APIKey) } resp, err := c.HTTPClient.Do(req) if err != nil { return nil, fmt.Errorf("making request: %w", err) } defer resp.Body.Close() if resp.StatusCode != 200 { return nil, fmt.Errorf("API error: %s", resp.Status) } body, err := io.ReadAll(resp.Body) if err != nil { return nil, fmt.Errorf("reading response: %w", err) } var response engine.ContentResponse if err := json.Unmarshal(body, &response); err != nil { return nil, fmt.Errorf("parsing response: %w", err) } // Convert slice to map for easy lookup result := make(map[string]engine.ContentItem) for _, item := range response.Content { result[item.ID] = item } return result, nil } // CreateContent creates a new content item via HTTP API func (c *HTTPClient) CreateContent(siteID, contentID, htmlContent, originalTemplate, lastEditedBy string) (*engine.ContentItem, error) { // For now, HTTPClient CreateContent is not implemented for enhancer use // This would typically be used in API-driven enhancement scenarios return nil, fmt.Errorf("CreateContent not implemented for HTTPClient - use DatabaseClient for enhancement") } // Collection method stubs - TODO: Implement these for HTTP API func (c *HTTPClient) GetCollection(siteID, collectionID string) (*engine.CollectionItem, error) { return nil, fmt.Errorf("collection operations not implemented in HTTPClient") } func (c *HTTPClient) CreateCollection(siteID, collectionID, containerHTML, lastEditedBy string) (*engine.CollectionItem, error) { return nil, fmt.Errorf("collection operations not implemented in HTTPClient") } func (c *HTTPClient) GetCollectionItems(siteID, collectionID string) ([]engine.CollectionItemWithTemplate, error) { return nil, fmt.Errorf("collection operations not implemented in HTTPClient") } func (c *HTTPClient) CreateCollectionTemplate(siteID, collectionID, name, htmlTemplate string, isDefault bool) (*engine.CollectionTemplateItem, error) { return nil, fmt.Errorf("collection operations not implemented in HTTPClient") } func (c *HTTPClient) GetCollectionTemplates(siteID, collectionID string) ([]engine.CollectionTemplateItem, error) { return nil, fmt.Errorf("collection operations not implemented in HTTPClient") } func (c *HTTPClient) CreateCollectionItem(siteID, collectionID, itemID string, templateID int, htmlContent string, position int, lastEditedBy string) (*engine.CollectionItemWithTemplate, error) { return nil, fmt.Errorf("collection operations not implemented in HTTPClient") }