package payments import ( "cmp" "slices" ) // catalogRank is the canonical listing key for a catalog product: whether it is a chip pack, its // value subgroup (see [valueGroup]; unused for a pack) and the minor-unit amount its section sorts by // (a pack's direct rouble price, a value's chip price; math.MaxInt64 when absent, so a misconfigured // row sorts last rather than leading). type catalogRank struct { pack bool group int amount int64 } // compareCatalogRank is the single canonical product order, shared by the storefront ([projectCatalog]), // the public offer ([projectOfferPricing]) and the admin catalog ([SortAdminCatalog]): chip packs // first, ascending by rouble price; then chip-priced values grouped hints → no-ads → combo → // tournament and, within a group, ascending by chip price. A pack's group is unused (all packs share // one section). Callers use it through [entryRank] / [adminRank], which build the key from each // product shape, so the subgroup and ordering rules live in exactly one place. func compareCatalogRank(a, b catalogRank) int { if a.pack != b.pack { if a.pack { return -1 // packs (sales) before values (chip exchange) } return 1 } if !a.pack { if d := cmp.Compare(a.group, b.group); d != 0 { return d } } return cmp.Compare(a.amount, b.amount) } // entryRank builds the canonical rank of a storefront / offer catalog entry. func entryRank(e catalogEntry) catalogRank { if isPackEntry(e) { return catalogRank{pack: true, amount: offerSortAmount(e, string(SourceDirect), CurrencyRUB)} } return catalogRank{group: offerValueGroup(e), amount: offerSortAmount(e, "", CurrencyChip)} } // adminRank builds the canonical rank of an admin catalog product. func adminRank(p AdminProduct) catalogRank { if adminIsPack(p) { return catalogRank{pack: true, amount: adminPriceAmount(p, string(SourceDirect), CurrencyRUB)} } return catalogRank{group: adminValueGroup(p), amount: adminPriceAmount(p, "", CurrencyChip)} } // sortCatalogEntries orders storefront / offer entries in place into the canonical listing order // ([compareCatalogRank]). Stable, so equal-keyed products keep their incoming (creation) order. func sortCatalogEntries(entries []catalogEntry) { slices.SortStableFunc(entries, func(a, b catalogEntry) int { return compareCatalogRank(entryRank(a), entryRank(b)) }) }