package api import ( "fmt" "io" "net/http" "time" "github.com/claudia/docs-cli/pkg/types" ) // ProjectsClient handles project API calls type ProjectsClient struct { client *Client } // NewProjectsClient creates a new projects client func NewProjectsClient(c *Client) *ProjectsClient { return &ProjectsClient{client: c} } // List lists all projects func (p *ProjectsClient) List() ([]types.Project, error) { resp, err := p.client.doRequest(http.MethodGet, "/projects", 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 projResp types.Response if err := decodeJSON(body, &projResp); err != nil { return nil, err } return sliceToProjects(projResp.Data), nil } // Get gets a project by ID func (p *ProjectsClient) Get(id string) (*types.Project, error) { resp, err := p.client.doRequest(http.MethodGet, "/projects/"+id, 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 projResp types.Response if err := decodeJSON(body, &projResp); err != nil { return nil, err } proj, ok := projResp.Data.(map[string]interface{}) if !ok { return nil, fmt.Errorf("unexpected response format") } return mapToProject(proj), nil } // Create creates a new project func (p *ProjectsClient) Create(req types.CreateProjectRequest) (*types.Project, error) { resp, err := p.client.doRequest(http.MethodPost, "/projects", req) 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.StatusCreated && resp.StatusCode != http.StatusOK { return nil, handleError(resp, body) } var projResp types.Response if err := decodeJSON(body, &projResp); err != nil { return nil, err } proj, ok := projResp.Data.(map[string]interface{}) if !ok { return nil, fmt.Errorf("unexpected response format") } return mapToProject(proj), nil } func mapToProject(m map[string]interface{}) *types.Project { proj := &types.Project{} if v, ok := m["id"].(string); ok { proj.ID = v } if v, ok := m["name"].(string); ok { proj.Name = v } if v, ok := m["description"].(string); ok { proj.Description = v } if v, ok := m["created_at"].(string); ok { proj.CreatedAt, _ = time.Parse(time.RFC3339, v) } if v, ok := m["updated_at"].(string); ok { proj.UpdatedAt, _ = time.Parse(time.RFC3339, v) } return proj } func sliceToProjects(data interface{}) []types.Project { var projects []types.Project if arr, ok := data.([]interface{}); ok { for _, item := range arr { if m, ok := item.(map[string]interface{}); ok { projects = append(projects, *mapToProject(m)) } } } return projects }