package repository

import (
	"fmt"
	"testing"
	"time"

	"git.mchus.pro/mchus/quoteforge/internal/models"
	"github.com/glebarez/sqlite"
	"gorm.io/gorm"
)

func TestGenerateVersion_FirstOfDay(t *testing.T) {
	repo := newTestPricelistRepository(t)

	version, err := repo.GenerateVersionBySource(string(models.PricelistSourceEstimate))
	if err != nil {
		t.Fatalf("GenerateVersionBySource returned error: %v", err)
	}

	today := time.Now().Format("2006-01-02")
	want := fmt.Sprintf("E-%s-001", today)
	if version != want {
		t.Fatalf("expected %s, got %s", want, version)
	}
}

func TestGenerateVersion_UsesMaxSuffixNotCount(t *testing.T) {
	repo := newTestPricelistRepository(t)
	today := time.Now().Format("2006-01-02")

	seed := []models.Pricelist{
		{Source: string(models.PricelistSourceEstimate), Version: fmt.Sprintf("E-%s-001", today), CreatedBy: "test", IsActive: true},
		{Source: string(models.PricelistSourceEstimate), Version: fmt.Sprintf("E-%s-003", today), CreatedBy: "test", IsActive: true},
	}
	for _, pl := range seed {
		if err := repo.Create(&pl); err != nil {
			t.Fatalf("seed insert failed: %v", err)
		}
	}

	version, err := repo.GenerateVersionBySource(string(models.PricelistSourceEstimate))
	if err != nil {
		t.Fatalf("GenerateVersionBySource returned error: %v", err)
	}

	want := fmt.Sprintf("E-%s-004", today)
	if version != want {
		t.Fatalf("expected %s, got %s", want, version)
	}
}

func TestGenerateVersion_IsolatedBySource(t *testing.T) {
	repo := newTestPricelistRepository(t)
	today := time.Now().Format("2006-01-02")

	seed := []models.Pricelist{
		{Source: string(models.PricelistSourceEstimate), Version: fmt.Sprintf("E-%s-009", today), CreatedBy: "test", IsActive: true},
		{Source: string(models.PricelistSourceWarehouse), Version: fmt.Sprintf("S-%s-002", today), CreatedBy: "test", IsActive: true},
	}
	for _, pl := range seed {
		if err := repo.Create(&pl); err != nil {
			t.Fatalf("seed insert failed: %v", err)
		}
	}

	version, err := repo.GenerateVersionBySource(string(models.PricelistSourceWarehouse))
	if err != nil {
		t.Fatalf("GenerateVersionBySource returned error: %v", err)
	}

	want := fmt.Sprintf("S-%s-003", today)
	if version != want {
		t.Fatalf("expected %s, got %s", want, version)
	}
}

func TestGetLatestActiveBySource_SkipsPricelistsWithoutItems(t *testing.T) {
	repo := newTestPricelistRepository(t)
	db := repo.db
	ts := time.Now().Add(-time.Minute)
	source := "test-estimate-skip-empty"

	emptyLatest := models.Pricelist{
		Source:    source,
		Version:   "E-empty",
		CreatedBy: "test",
		IsActive:  true,
		CreatedAt: ts.Add(2 * time.Second),
	}
	if err := db.Create(&emptyLatest).Error; err != nil {
		t.Fatalf("create empty pricelist: %v", err)
	}

	withItems := models.Pricelist{
		Source:    source,
		Version:   "E-with-items",
		CreatedBy: "test",
		IsActive:  true,
		CreatedAt: ts,
	}
	if err := db.Create(&withItems).Error; err != nil {
		t.Fatalf("create pricelist with items: %v", err)
	}
	if err := db.Create(&models.PricelistItem{
		PricelistID: withItems.ID,
		LotName:     "CPU_A",
		Price:       100,
	}).Error; err != nil {
		t.Fatalf("create pricelist item: %v", err)
	}

	got, err := repo.GetLatestActiveBySource(source)
	if err != nil {
		t.Fatalf("GetLatestActiveBySource: %v", err)
	}
	if got.ID != withItems.ID {
		t.Fatalf("expected pricelist with items id=%d, got id=%d", withItems.ID, got.ID)
	}
}

func TestGetLatestActiveBySource_TieBreaksByID(t *testing.T) {
	repo := newTestPricelistRepository(t)
	db := repo.db
	ts := time.Now().Add(-time.Minute)
	source := "test-warehouse-tie-break"

	first := models.Pricelist{
		Source:    source,
		Version:   "S-1",
		CreatedBy: "test",
		IsActive:  true,
		CreatedAt: ts,
	}
	if err := db.Create(&first).Error; err != nil {
		t.Fatalf("create first pricelist: %v", err)
	}
	if err := db.Create(&models.PricelistItem{
		PricelistID: first.ID,
		LotName:     "CPU_A",
		Price:       101,
	}).Error; err != nil {
		t.Fatalf("create first item: %v", err)
	}

	second := models.Pricelist{
		Source:    source,
		Version:   "S-2",
		CreatedBy: "test",
		IsActive:  true,
		CreatedAt: ts,
	}
	if err := db.Create(&second).Error; err != nil {
		t.Fatalf("create second pricelist: %v", err)
	}
	if err := db.Create(&models.PricelistItem{
		PricelistID: second.ID,
		LotName:     "CPU_A",
		Price:       102,
	}).Error; err != nil {
		t.Fatalf("create second item: %v", err)
	}

	got, err := repo.GetLatestActiveBySource(source)
	if err != nil {
		t.Fatalf("GetLatestActiveBySource: %v", err)
	}
	if got.ID != second.ID {
		t.Fatalf("expected later inserted pricelist id=%d, got id=%d", second.ID, got.ID)
	}
}

func newTestPricelistRepository(t *testing.T) *PricelistRepository {
	t.Helper()

	db, err := gorm.Open(sqlite.Open("file::memory:?cache=shared"), &gorm.Config{})
	if err != nil {
		t.Fatalf("open sqlite: %v", err)
	}
	if err := db.AutoMigrate(&models.Pricelist{}, &models.PricelistItem{}, &models.Lot{}); err != nil {
		t.Fatalf("migrate: %v", err)
	}
	return NewPricelistRepository(db)
}
