package api import ( "fmt" "io" "net/http" "net/url" "github.com/claudia/docs-cli/pkg/types" ) // SearchClient handles search API calls type SearchClient struct { client *Client } // NewSearchClient creates a new search client func NewSearchClient(c *Client) *SearchClient { return &SearchClient{client: c} } // Search performs a full-text search func (s *SearchClient) Search(query, projectID, tags string) (*types.SearchResult, error) { params := url.Values{} params.Set("q", query) if projectID != "" { params.Set("project_id", projectID) } if tags != "" { params.Set("tags", tags) } path := "/search?" + params.Encode() resp, err := s.client.doRequest(http.MethodGet, path, nil) if err != nil { return nil, err } defer resp.Body.Close() body, err := io.ReadAll(resp.Body) if err != nil { return nil, fmt.Errorf("failed to read response: %w", err) } if resp.StatusCode != http.StatusOK { return nil, handleError(resp, body) } var searchResp types.Response if err := decodeJSON(body, &searchResp); err != nil { return nil, err } return mapToSearchResult(searchResp.Data, query), nil } func mapToSearchResult(data interface{}, query string) *types.SearchResult { result := &types.SearchResult{Query: query} if m, ok := data.(map[string]interface{}); ok { if v, ok := m["documents"].([]interface{}); ok { for _, item := range v { if doc, ok := item.(map[string]interface{}); ok { result.Documents = append(result.Documents, *mapToDocument(doc)) } } } if v, ok := m["total"].(float64); ok { result.Total = int(v) } } return result }