package api import ( "bytes" "encoding/json" "fmt" "io" "net/http" "time" "github.com/nutcas3/telecom-platform/apps/cli/internal/types" ) // Client represents the API client for the telecom platform type Client struct { baseURL string apiKey string httpClient *http.Client } // NewClient creates a new API client from CLI config func NewClient(cfg *types.CLIConfig) *Client { if cfg == nil { cfg = &types.CLIConfig{APIEndpoint: "http://localhost:8000"} } return &Client{ baseURL: cfg.APIEndpoint, apiKey: cfg.APIToken, httpClient: &http.Client{ Timeout: 30 * time.Second, }, } } // BaseURL returns the configured API endpoint (useful for UI display). func (c *Client) BaseURL() string { return c.baseURL } // doGetJSON performs a GET request and decodes JSON into out func (c *Client) doGetJSON(path string, out any) error { req, err := http.NewRequest("GET", c.baseURL+path, nil) if err != nil { return err } if c.apiKey != "" { req.Header.Set("Authorization", "Bearer "+c.apiKey) } req.Header.Set("Content-Type", "application/json") resp, err := c.httpClient.Do(req) if err != nil { return err } defer resp.Body.Close() if resp.StatusCode >= 400 { body, _ := io.ReadAll(resp.Body) return fmt.Errorf("API %s %d: %s", path, resp.StatusCode, string(body)) } return json.NewDecoder(resp.Body).Decode(out) } // doPostJSON performs a POST request with JSON body and decodes response func (c *Client) doPostJSON(path string, body any, out any) error { var buf *bytes.Buffer if body != nil { b, err := json.Marshal(body) if err != nil { return err } buf = bytes.NewBuffer(b) } else { buf = bytes.NewBuffer(nil) } req, err := http.NewRequest("POST", c.baseURL+path, buf) if err != nil { return err } if c.apiKey != "" { req.Header.Set("Authorization", "Bearer "+c.apiKey) } req.Header.Set("Content-Type", "application/json") resp, err := c.httpClient.Do(req) if err != nil { return err } defer resp.Body.Close() if resp.StatusCode >= 400 { rb, _ := io.ReadAll(resp.Body) return fmt.Errorf("API %s %d: %s", path, resp.StatusCode, string(rb)) } if out == nil { return nil } return json.NewDecoder(resp.Body).Decode(out) } // doDelete performs a DELETE request func (c *Client) doDelete(path string) error { req, err := http.NewRequest("DELETE", c.baseURL+path, nil) if err != nil { return err } if c.apiKey != "" { req.Header.Set("Authorization", "Bearer "+c.apiKey) } resp, err := c.httpClient.Do(req) if err != nil { return err } defer resp.Body.Close() if resp.StatusCode >= 400 { body, _ := io.ReadAll(resp.Body) return fmt.Errorf("API %s %d: %s", path, resp.StatusCode, string(body)) } return nil } // IsConnected checks if the API server is reachable func (c *Client) IsConnected() bool { url := fmt.Sprintf("%s/health", c.baseURL) req, err := http.NewRequest("GET", url, nil) if err != nil { return false } req.Header.Set("Authorization", "Bearer "+c.apiKey) resp, err := c.httpClient.Do(req) if err != nil { return false } defer resp.Body.Close() return resp.StatusCode == http.StatusOK }