package db import ( "context" "encoding/json" "fmt" "io" "net/http" "net/url" "strings" "time" ) // HTTPClient implements ContentRepository 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(ctx context.Context, siteID, contentID string) (*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 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(ctx context.Context, siteID string, contentIDs []string) (map[string]ContentItem, error) { if len(contentIDs) == 0 { return make(map[string]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 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]ContentItem) for _, item := range response.Content { result[item.ID] = item } return result, nil } // GetAllContent fetches all content for a site func (c *HTTPClient) GetAllContent(ctx context.Context, siteID string) (map[string]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 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]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(ctx context.Context, siteID, contentID, htmlContent, originalTemplate, lastEditedBy string) (*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(ctx context.Context, siteID, collectionID string) (*CollectionItem, error) { return nil, fmt.Errorf("collection operations not implemented in HTTPClient") } func (c *HTTPClient) CreateCollection(ctx context.Context, siteID, collectionID, containerHTML, lastEditedBy string) (*CollectionItem, error) { return nil, fmt.Errorf("collection operations not implemented in HTTPClient") } func (c *HTTPClient) GetCollectionItems(ctx context.Context, siteID, collectionID string) ([]CollectionItemWithTemplate, error) { return nil, fmt.Errorf("collection operations not implemented in HTTPClient") } func (c *HTTPClient) CreateCollectionTemplate(ctx context.Context, siteID, collectionID, name, htmlTemplate string, isDefault bool) (*CollectionTemplateItem, error) { return nil, fmt.Errorf("collection operations not implemented in HTTPClient") } func (c *HTTPClient) GetCollectionTemplates(ctx context.Context, siteID, collectionID string) ([]CollectionTemplateItem, error) { return nil, fmt.Errorf("collection operations not implemented in HTTPClient") } func (c *HTTPClient) GetCollectionTemplate(ctx context.Context, templateID int) (*CollectionTemplateItem, error) { return nil, fmt.Errorf("collection operations not implemented in HTTPClient") } func (c *HTTPClient) CreateCollectionItem(ctx context.Context, siteID, collectionID, itemID string, templateID int, htmlContent string, position int, lastEditedBy string) (*CollectionItemWithTemplate, error) { return nil, fmt.Errorf("collection operations not implemented in HTTPClient") } func (c *HTTPClient) CreateCollectionItemAtomic(ctx context.Context, siteID, collectionID string, templateID int, lastEditedBy string) (*CollectionItemWithTemplate, error) { return nil, fmt.Errorf("collection operations not implemented in HTTPClient") } func (c *HTTPClient) GetMaxPosition(ctx context.Context, siteID, collectionID string) (int, error) { return 0, fmt.Errorf("collection operations not implemented in HTTPClient") } func (c *HTTPClient) UpdateContent(ctx context.Context, siteID, contentID, htmlContent, lastEditedBy string) (*ContentItem, error) { return nil, fmt.Errorf("content update operations not implemented in HTTPClient") } func (c *HTTPClient) ReorderCollectionItems(ctx context.Context, siteID, collectionID string, items []CollectionItemPosition, lastEditedBy string) error { return fmt.Errorf("collection reordering not implemented in HTTPClient") } // WithTransaction executes a function within a transaction (not supported for HTTP client) func (c *HTTPClient) WithTransaction(ctx context.Context, fn func(ContentRepository) error) error { return fmt.Errorf("transactions not supported for HTTP client") }