// Package render is the backend's client for the internal image-render sidecar: it POSTs
// a finished game's export payload and receives the rasterized PNG. The sidecar runs the
// same drawing code the web client unit-tests (ui/src/lib/gameimage.ts on skia-canvas);
// authentication and the signed public URL live in the server layer — this client only
// carries bytes.
package render

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"time"
)

// maxPNG caps a render response; a scale-2 export of the largest plausible game is well
// under 2 MiB, so anything bigger is a sidecar malfunction, not a valid image.
const maxPNG = 8 << 20

// Client calls the render sidecar over the internal network.
type Client struct {
	base string
	http *http.Client
}

// New returns a client for the sidecar at baseURL (e.g. http://renderer:8090). A render
// of a full game takes well under a second; the timeout leaves room for a cold start.
func New(baseURL string) *Client {
	return &Client{base: baseURL, http: &http.Client{Timeout: 15 * time.Second}}
}

// Render posts payload (the JSON request shape the sidecar consumes) and returns the PNG.
func (c *Client) Render(ctx context.Context, payload any) ([]byte, error) {
	body, err := json.Marshal(payload)
	if err != nil {
		return nil, fmt.Errorf("render: marshal payload: %w", err)
	}
	req, err := http.NewRequestWithContext(ctx, http.MethodPost, c.base+"/render", bytes.NewReader(body))
	if err != nil {
		return nil, fmt.Errorf("render: build request: %w", err)
	}
	req.Header.Set("Content-Type", "application/json")
	resp, err := c.http.Do(req)
	if err != nil {
		return nil, fmt.Errorf("render: %w", err)
	}
	defer resp.Body.Close()
	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("render: sidecar status %d", resp.StatusCode)
	}
	png, err := io.ReadAll(io.LimitReader(resp.Body, maxPNG+1))
	if err != nil {
		return nil, fmt.Errorf("render: read response: %w", err)
	}
	if len(png) > maxPNG {
		return nil, fmt.Errorf("render: response exceeds %d bytes", maxPNG)
	}
	return png, nil
}
