package payments

// AtomQty is one atom line of a catalog product in the read model: the base value type it grants
// (chips / hints / no-ads days / tournament) and how many of it the product carries.
type AtomQty struct {
	AtomType string
	Quantity int
}

// CatalogProduct is one storefront product projected for the execution context. A value is
// bought with chips, so it carries Chips (its uniform chip price) and no money price. A chip pack
// funds chips with money, so it carries MoneyAmount (minor units) and MoneyCurrency for the
// context's payment method and no chip price. Atoms lists what the product grants.
type CatalogProduct struct {
	Kind          string // "value" (bought with chips) or "pack" (funds chips with money)
	ProductID     string
	Title         string
	Chips         int    // a value's uniform chip price; 0 for a pack
	MoneyAmount   int64  // a pack's price in the context currency's minor units; 0 for a value
	MoneyCurrency string // a pack's currency for the context method; empty for a value
	Atoms         []AtomQty
}

// CatalogView is the storefront read model for one execution context: the products a player sees
// and can buy there — every chip-priced value plus the chip packs priced in the context's method.
type CatalogView struct {
	Products []CatalogProduct
}

// atomChips is the atom type that marks a product as a chip pack (it funds chips) rather than a
// value (bought with chips). A value never carries it.
const atomChips = "chips"

// projectCatalog turns the raw active catalog into the storefront for the context. A value (no
// chips atom) is shown everywhere at its CHIP price. A chip pack is shown only when it carries a
// price for the context's payment method (cxt.Kind: vk / telegram / direct), priced in that
// method's currency. A value missing its CHIP price and a pack missing a price for the context
// method are omitted (misconfigured or unavailable there). An untrusted context (empty Kind) has
// no method, so only values show; buying is gated server-side regardless.
func projectCatalog(entries []catalogEntry, cxt Context) CatalogView {
	// Present products in the canonical listing order shared with the offer and the admin console
	// (packs first by rouble price, then values grouped hints → no-ads → combo and by chip price); the
	// client renders them as received. Ordered in place — the caller passes a fresh loadCatalog result
	// it does not reuse.
	sortCatalogEntries(entries)
	var out CatalogView
	for _, e := range entries {
		isPack := false
		atoms := make([]AtomQty, 0, len(e.atoms))
		for _, a := range e.atoms {
			atoms = append(atoms, AtomQty{AtomType: a.atomType, Quantity: a.quantity})
			if a.atomType == atomChips {
				isPack = true
			}
		}
		p := CatalogProduct{ProductID: e.id.String(), Title: e.title, Atoms: atoms}
		if isPack {
			pr, ok := findPrice(e.prices, string(cxt.Kind))
			if !ok {
				continue // no price for this context's method — not purchasable here
			}
			p.Kind = "pack"
			p.MoneyAmount = pr.amount
			p.MoneyCurrency = string(pr.currency)
		} else {
			pr, ok := findPrice(e.prices, "")
			if !ok {
				continue // a value must carry a CHIP price
			}
			p.Kind = "value"
			p.Chips = int(pr.amount)
		}
		out.Products = append(out.Products, p)
	}
	return out
}

// findPrice returns the price row for the given payment method — the empty string selects a
// value's CHIP price row (stored with a NULL method).
func findPrice(prices []priceRow, method string) (priceRow, bool) {
	for _, pr := range prices {
		if pr.method == method {
			return pr, true
		}
	}
	return priceRow{}, false
}
