package integration

import (
	"context"
	"testing"

	"github.com/shopspring/decimal"

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

// TestCatalogListSearchPagination runs the category/unit list queries against
// real Postgres: search must filter, pagination must slice, and the total
// must count the filtered set rather than the page. The service-level fakes
// cannot prove the SQL does any of this, and the categories page showed all
// three failing at once on live data (unfiltered search, pager changing
// nothing) because the old queries had no search predicate and no total.
func TestCatalogListSearchPagination(t *testing.T) {
	pool := testPool(t)
	setUp(t, pool)
	ctx := context.Background()

	svc := catalog.NewService(catalog.NewRepository(pool), seqAdapter{pool}, wib)

	names := []string{"MakananRingan", "MinumanDingin", "MakananBerat"}
	for _, n := range names {
		if _, err := svc.CreateCategory(ctx, catalog.CategoryInput{Name: unique(n), IsActive: true}); err != nil {
			t.Fatalf("create category %s: %v", n, err)
		}
	}

	found, total, err := svc.ListCategories(ctx, catalog.CatalogFilter{Search: "makanan"})
	if err != nil {
		t.Fatalf("search categories: %v", err)
	}
	if total != 2 {
		t.Errorf("search total = %d, want 2", total)
	}
	if len(found) != 2 {
		t.Errorf("search rows = %d, want 2", len(found))
	}

	p1, total, err := svc.ListCategories(ctx, catalog.CatalogFilter{Page: 1, PerPage: 2})
	if err != nil {
		t.Fatalf("page 1: %v", err)
	}
	p2, _, err := svc.ListCategories(ctx, catalog.CatalogFilter{Page: 2, PerPage: 2})
	if err != nil {
		t.Fatalf("page 2: %v", err)
	}
	if total != 3 {
		t.Errorf("total = %d, want 3", total)
	}
	if len(p1) != 2 || len(p2) != 1 {
		t.Fatalf("page sizes = %d/%d, want 2/1", len(p1), len(p2))
	}
	if p1[0].ID == p2[0].ID {
		t.Errorf("both pages start with id %d: the pager renders the same row twice", p1[0].ID)
	}

	// Units follow the same contract through the same filter type.
	for _, u := range [][2]string{{"KilogramX", "kgx"}, {"GramX", "gx"}, {"BoxX", "box"}} {
		if _, err := svc.CreateUnit(ctx, catalog.UnitInput{Name: unique(u[0]), Symbol: u[1]}); err != nil {
			t.Fatalf("create unit %s: %v", u[0], err)
		}
	}
	ulist, utotal, err := svc.ListUnits(ctx, catalog.CatalogFilter{Search: "box"})
	if err != nil {
		t.Fatalf("search units: %v", err)
	}
	if utotal != 1 || len(ulist) != 1 {
		t.Errorf("unit search total/rows = %d/%d, want 1/1", utotal, len(ulist))
	}
	up2, utotal2, err := svc.ListUnits(ctx, catalog.CatalogFilter{Page: 2, PerPage: 2})
	if err != nil {
		t.Fatalf("units page 2: %v", err)
	}
	if utotal2 != 3 || len(up2) != 1 {
		t.Errorf("unit total/page2 = %d/%d, want 3/1", utotal2, len(up2))
	}
}

// A per_page above 100 used to be silently reset to 20, so the catalog page
// asking per_page=200 received only the first 20 products and late-sorting
// ones never reached the browser — the Depot Galon filter showed empty for
// exactly this reason. 25 rows distinguish the fixed cap from the old one.
func TestCatalogListProducts_LargePageNotTruncated(t *testing.T) {
	pool := testPool(t)
	setUp(t, pool)
	ctx := context.Background()

	svc := catalog.NewService(catalog.NewRepository(pool), seqAdapter{pool}, wib)

	cat := seedCategory(t, pool)
	unit := seedUnit(t, pool)
	for i := 0; i < 25; i++ {
		if _, err := svc.CreateProduct(ctx, catalog.ProductInput{
			Name:          unique("CAP"),
			CategoryID:    cat,
			UnitID:        unit,
			PurchasePrice: decimal.NewFromInt(1000),
			SellingPrice:  decimal.NewFromInt(1500),
		}); err != nil {
			t.Fatalf("create product %d: %v", i, err)
		}
	}

	list, total, err := svc.ListProducts(ctx, catalog.ProductFilter{Page: 1, PerPage: 200})
	if err != nil {
		t.Fatalf("list products: %v", err)
	}
	if total != 25 {
		t.Errorf("total = %d, want 25", total)
	}
	if len(list) != 25 {
		t.Errorf("rows = %d, want 25 (a silent per_page reset truncates to 20)", len(list))
	}
}
