package lhpp

import (
	"context"

	"github.com/jackc/pgx/v5/pgxpool"

	"github.com/TaruLab/keluargamart-backend/internal/db"
)

// Tx is a physical transaction. pgx.Tx satisfies it.
type Tx interface {
	db.DBTX
	Commit(ctx context.Context) error
	Rollback(ctx context.Context) error
}

// Repository reads the flat candidate rows LHPP sheets are built from, and
// performs the group maintenance writes (merge / split / void / the dispatch
// seam). Reads stay on the pool; every membership change opens its own
// transaction so the DO locks, the group locks, the number allocation and the
// history rows all commit or roll back together.
type Repository struct {
	pool *pgxpool.Pool
	q    *db.Queries
}

func NewRepository(pool *pgxpool.Pool) *Repository {
	return &Repository{pool: pool, q: db.New(pool)}
}

// Begin starts the transaction every membership change runs in.
func (r *Repository) Begin(ctx context.Context) (Tx, error) {
	return r.pool.Begin(ctx)
}

// Q re-binds the generated queries onto a transaction. Passed to callers that
// need to run several of them atomically.
func (r *Repository) Q(tx db.DBTX) *db.Queries {
	return db.New(tx)
}

func (r *Repository) CandidateRows(ctx context.Context) ([]db.ListLHPPCandidateRowsRow, error) {
	return r.q.ListLHPPCandidateRows(ctx)
}

// SalesCandidateRows returns the flat rows Sales LHPP groups are built from:
// every billing visit joined to its customer's open invoices. Sales LHPP is
// untouched by the driver-side grouping rework: it is a scheduled-visit
// worksheet, not a delivery-order sheet, and it is still computed on read.
func (r *Repository) SalesCandidateRows(ctx context.Context) ([]db.ListLHPPSalesCandidateRowsRow, error) {
	return r.q.ListLHPPSalesCandidateRows(ctx)
}

// CashGiroPaymentsForInvoices returns every cash/giro payment recorded
// against this set of invoices, with its Setoran linkage (deposit_id, nil
// until a Setoran Tunai Driver picks it up). Used to derive each LHPP item's
// deposit status precisely instead of approximating by driver+date.
func (r *Repository) CashGiroPaymentsForInvoices(ctx context.Context, invoiceIDs []int64) ([]db.LHPPCashGiroPaymentsForInvoicesRow, error) {
	if len(invoiceIDs) == 0 {
		return nil, nil
	}
	return r.q.LHPPCashGiroPaymentsForInvoices(ctx, invoiceIDs)
}

// GroupByID returns a group header, INCLUDING a voided one — Get must still
// reach a retired sheet by id so its number stays auditable.
func (r *Repository) GroupByID(ctx context.Context, q *db.Queries, id int64) (db.LHPPGetGroupRow, error) {
	return q.LHPPGetGroup(ctx, id)
}
