package service

import (
	"testing"

	"github.com/glebarez/sqlite"
	"gorm.io/gorm"
)

func TestApplyWarehouseSelectionFilterIncludesFarmAndSelectedKandangInLocation(t *testing.T) {
	db := setupProductWarehouseServiceTestDB(t)

	var ids []uint
	err := applyWarehouseSelectionFilter(baseProductWarehouseSelectionQuery(db), 11, 101).
		Order("product_warehouses.id").
		Pluck("product_warehouses.id", &ids).Error
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

	assertUintIDs(t, ids, []uint{1, 2})
}

func TestApplyWarehouseSelectionFilterPreservesKandangOnlyBehavior(t *testing.T) {
	db := setupProductWarehouseServiceTestDB(t)

	var ids []uint
	err := applyWarehouseSelectionFilter(baseProductWarehouseSelectionQuery(db), 11, 0).
		Order("product_warehouses.id").
		Pluck("product_warehouses.id", &ids).Error
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

	assertUintIDs(t, ids, []uint{1})
}

func TestApplyWarehouseSelectionFilterSupportsLocationOnlyQuery(t *testing.T) {
	db := setupProductWarehouseServiceTestDB(t)

	var ids []uint
	err := applyWarehouseSelectionFilter(baseProductWarehouseSelectionQuery(db), 0, 101).
		Order("product_warehouses.id").
		Pluck("product_warehouses.id", &ids).Error
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

	assertUintIDs(t, ids, []uint{1, 2, 3})
}

func TestApplyAvailableOnlyFilterRemovesZeroQtyRows(t *testing.T) {
	db := setupProductWarehouseServiceTestDB(t)

	var ids []uint
	err := applyAvailableOnlyFilter(baseProductWarehouseSelectionQuery(db), true).
		Order("product_warehouses.id").
		Pluck("product_warehouses.id", &ids).Error
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

	assertUintIDs(t, ids, []uint{1, 2, 4})
}

func setupProductWarehouseServiceTestDB(t *testing.T) *gorm.DB {
	t.Helper()

	db, err := gorm.Open(sqlite.Open("file:"+t.Name()+"?mode=memory&cache=private"), &gorm.Config{})
	if err != nil {
		t.Fatalf("failed opening sqlite db: %v", err)
	}

	statements := []string{
		`CREATE TABLE warehouses (
			id INTEGER PRIMARY KEY,
			type TEXT NOT NULL,
			location_id INTEGER NULL,
			kandang_id INTEGER NULL,
			deleted_at TIMESTAMP NULL
		)`,
		`CREATE TABLE product_warehouses (
			id INTEGER PRIMARY KEY,
			warehouse_id INTEGER NOT NULL,
			qty NUMERIC NULL
		)`,
		`INSERT INTO warehouses (id, type, location_id, kandang_id, deleted_at) VALUES
			(1, 'KANDANG', 101, 11, NULL),
			(2, 'LOKASI', 101, NULL, NULL),
			(3, 'KANDANG', 101, 12, NULL),
			(4, 'LOKASI', 102, NULL, NULL)`,
		`INSERT INTO product_warehouses (id, warehouse_id, qty) VALUES
			(1, 1, 10),
			(2, 2, 20),
			(3, 3, 0),
			(4, 4, 15)`,
	}

	for _, stmt := range statements {
		if err := db.Exec(stmt).Error; err != nil {
			t.Fatalf("failed preparing schema: %v", err)
		}
	}

	return db
}

func baseProductWarehouseSelectionQuery(db *gorm.DB) *gorm.DB {
	return db.Table("product_warehouses").
		Joins("JOIN warehouses w_scope ON product_warehouses.warehouse_id = w_scope.id").
		Where("w_scope.deleted_at IS NULL")
}

func assertUintIDs(t *testing.T, got []uint, want []uint) {
	t.Helper()

	if len(got) != len(want) {
		t.Fatalf("expected ids %v, got %v", want, got)
	}

	for i := range want {
		if got[i] != want[i] {
			t.Fatalf("expected ids %v, got %v", want, got)
		}
	}
}
