// Package paddle is the only place that talks to Paddle. Everything outside it
// depends on the Client interface and our own types, never on Paddle's wire
// shapes — so a change at Paddle is confined to http.go, and the billing package
// can be reasoned about without knowing Paddle exists.
//
// It is a thin REST client rather than the vendor SDK on purpose: the surface we
// need is two calls, and a hand-rolled client has no version-drift risk and no
// dependency to keep in go.sum.
package paddle

import "context"

// LineItem is one price at a quantity, the shape both a checkout and a
// subscription update are built from.
type LineItem struct {
	PriceID  string
	Quantity int
}

// Client is the narrow slice of Paddle admin needs. Checkout itself happens in
// the browser via paddle-js; the server only updates an existing subscription
// and mints a portal session.
type Client interface {
	// UpdateSubscriptionItems replaces a subscription's items, prorated
	// immediately by Paddle. This is the one outbound mutation, used when a
	// customer changes their server count or features on an existing plan.
	UpdateSubscriptionItems(ctx context.Context, paddleSubscriptionID string, items []LineItem) error
	// UpdateSubscriptionCustomData replaces a subscription's custom_data. Used
	// when a self-hosted placeholder is claimed: the checkout attached the
	// placeholder id, and every later webhook must name the real install UUID.
	UpdateSubscriptionCustomData(ctx context.Context, paddleSubscriptionID string, data map[string]string) error
	// PortalSession returns a customer-portal URL for managing billing.
	PortalSession(ctx context.Context, paddleCustomerID string) (string, error)
	// Env is "sandbox" or "production", the same value catalogue price lookups
	// are keyed on.
	Env() string
}

var current Client

// Init constructs the client from config and stores it. Called once at boot.
func Init(apiKey, env string) (Client, error) {
	c, err := newHTTPClient(apiKey, env)
	if err != nil {
		return nil, err
	}
	current = c
	return c, nil
}

// Get returns the client initialised at boot. Panics if unset, which can only
// happen if a caller runs before Init — a programming error, not a runtime one.
func Get() Client {
	if current == nil {
		panic("paddle.Get before paddle.Init")
	}
	return current
}
