package payments

import (
	"context"
	"fmt"

	"github.com/go-jet/jet/v2/postgres"
	"github.com/google/uuid"

	"scrabble/backend/internal/postgres/jet/payments/model"
	"scrabble/backend/internal/postgres/jet/payments/table"
)

// atomQty is one atom line of a product as loaded from the catalog: the atom type and quantity.
type atomQty struct {
	atomType string
	quantity int
}

// priceRow is one price of a product as loaded from the catalog: the payment method (empty for a
// value's CHIP price, stored with a NULL method) and the amount in that currency's minor units.
type priceRow struct {
	method   string
	currency Currency
	amount   int64
}

// catalogEntry is a raw active product loaded for the storefront: its atom composition and every
// price row. [projectCatalog] turns it into the context-visible [CatalogProduct].
type catalogEntry struct {
	id     uuid.UUID
	title  string
	atoms  []atomQty
	prices []priceRow
}

// loadCatalog reads every active product with its atoms and prices, ordered by creation, straight
// from the catalog tables. The catalog is small and rarely edited (admin console only), so it is
// read uncached — unlike the per-account balances/benefits the read cache fronts.
func (s *Store) loadCatalog(ctx context.Context) ([]catalogEntry, error) {
	var prods []model.Product
	if err := postgres.SELECT(table.Product.AllColumns).
		FROM(table.Product).
		WHERE(table.Product.Active.IS_TRUE()).
		ORDER_BY(table.Product.CreatedAt.ASC()).
		QueryContext(ctx, s.db, &prods); err != nil {
		return nil, fmt.Errorf("payments: load catalog products: %w", err)
	}
	if len(prods) == 0 {
		return nil, nil
	}
	entries := make([]catalogEntry, len(prods))
	index := make(map[uuid.UUID]int, len(prods))
	for i, p := range prods {
		entries[i] = catalogEntry{id: p.ProductID, title: p.Title}
		index[p.ProductID] = i
	}

	var items []model.ProductItem
	if err := postgres.SELECT(table.ProductItem.AllColumns).
		FROM(table.ProductItem).
		QueryContext(ctx, s.db, &items); err != nil {
		return nil, fmt.Errorf("payments: load catalog items: %w", err)
	}
	for _, it := range items {
		if i, ok := index[it.ProductID]; ok {
			entries[i].atoms = append(entries[i].atoms, atomQty{atomType: it.AtomType, quantity: int(it.Quantity)})
		}
	}

	var prices []model.ProductPrice
	if err := postgres.SELECT(table.ProductPrice.AllColumns).
		FROM(table.ProductPrice).
		QueryContext(ctx, s.db, &prices); err != nil {
		return nil, fmt.Errorf("payments: load catalog prices: %w", err)
	}
	for _, pr := range prices {
		i, ok := index[pr.ProductID]
		if !ok {
			continue // a price for a deactivated product — not in the storefront
		}
		method := ""
		if pr.Method != nil {
			method = *pr.Method
		}
		entries[i].prices = append(entries[i].prices, priceRow{method: method, currency: Currency(pr.Currency), amount: pr.Amount})
	}
	return entries, nil
}
