package render import ( "encoding/json" "fmt" "io" "github.com/kotoyuuko/zenmux-usage-cli/internal/api" ) // jsonAccountEntry is the shape of each element in multi-account JSON mode. type jsonAccountEntry struct { Account string `json:"account"` Success bool `json:"success"` Data *api.Data `json:"data"` Error *string `json:"error"` } // RenderJSONSingle writes the raw API body to w with a trailing newline. // Used when exactly one account was resolved — preserves the exact shape // returned by the API so `jq .data.plan.tier` keeps working. func RenderJSONSingle(w io.Writer, raw []byte) error { if _, err := w.Write(raw); err != nil { return err } if len(raw) == 0 || raw[len(raw)-1] != '\n' { if _, err := w.Write([]byte{'\n'}); err != nil { return err } } return nil } // RenderJSONMulti emits an ordered JSON array with one object per result. // Successful entries have data populated and error: null; failed entries // have data: null and a non-empty error message. func RenderJSONMulti(w io.Writer, results []AccountResult) error { out := make([]jsonAccountEntry, len(results)) for i, r := range results { entry := jsonAccountEntry{Account: r.Name} switch { case r.Err != nil: entry.Success = false msg := r.Err.Error() entry.Error = &msg case r.Response == nil: entry.Success = false msg := "no response" entry.Error = &msg default: entry.Success = r.Response.Success entry.Data = &r.Response.Data if !r.Response.Success { msg := r.Response.Error if msg == "" { msg = "api returned success=false" } entry.Error = &msg entry.Data = nil } } out[i] = entry } enc := json.NewEncoder(w) enc.SetIndent("", " ") if err := enc.Encode(out); err != nil { return fmt.Errorf("encode multi-account json: %w", err) } return nil }