package sync

import (
	"path/filepath"
	"testing"
	"time"

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

func TestSyncNewPricelistSnapshotUpsertsExistingServerID(t *testing.T) {
	local := newLocalDBForUpsertTest(t)
	serverDB := newServerDBForUpsertTest(t)
	if err := serverDB.AutoMigrate(&models.Pricelist{}, &models.PricelistItem{}); err != nil {
		t.Fatalf("migrate server pricelist tables: %v", err)
	}

	serverPL := models.Pricelist{
		Source:       "estimate",
		Version:      "B-2026-04-28-001",
		Notification: "server-current",
		CreatedBy:    "tester",
		IsActive:     true,
		CreatedAt:    time.Now().Add(-1 * time.Hour),
	}
	if err := serverDB.Create(&serverPL).Error; err != nil {
		t.Fatalf("create server pricelist: %v", err)
	}
	if err := serverDB.Create(&models.PricelistItem{PricelistID: serverPL.ID, LotName: "CPU_A", Price: 10}).Error; err != nil {
		t.Fatalf("create server pricelist item: %v", err)
	}

	if err := local.SaveLocalPricelist(&localdb.LocalPricelist{
		ServerID:  serverPL.ID,
		Source:    "estimate",
		Version:   "old-version",
		Name:      "stale-local",
		CreatedAt: time.Now().Add(-24 * time.Hour),
		SyncedAt:  time.Now().Add(-24 * time.Hour),
		IsUsed:    false,
	}); err != nil {
		t.Fatalf("seed stale local pricelist: %v", err)
	}
	staleLocal, err := local.GetLocalPricelistByServerID(serverPL.ID)
	if err != nil {
		t.Fatalf("get stale local pricelist: %v", err)
	}
	if err := local.SaveLocalPricelistItems([]localdb.LocalPricelistItem{
		{PricelistID: staleLocal.ID, LotName: "OLD_LOT", Price: 99},
	}); err != nil {
		t.Fatalf("seed stale local pricelist items: %v", err)
	}

	svc := NewServiceWithDB(serverDB, local)
	localPL := &localdb.LocalPricelist{
		ServerID:  serverPL.ID,
		Source:    serverPL.Source,
		Version:   serverPL.Version,
		Name:      serverPL.Notification,
		CreatedAt: serverPL.CreatedAt,
		SyncedAt:  time.Now(),
		IsUsed:    false,
	}

	itemCount, err := svc.syncNewPricelistSnapshot(localPL)
	if err != nil {
		t.Fatalf("sync new pricelist snapshot: %v", err)
	}
	if itemCount != 1 {
		t.Fatalf("expected 1 synced item, got %d", itemCount)
	}

	refreshed, err := local.GetLocalPricelistByServerID(serverPL.ID)
	if err != nil {
		t.Fatalf("get refreshed local pricelist: %v", err)
	}
	if refreshed.Version != serverPL.Version {
		t.Fatalf("expected local version %q, got %q", serverPL.Version, refreshed.Version)
	}
	if refreshed.Name != serverPL.Notification {
		t.Fatalf("expected local name %q, got %q", serverPL.Notification, refreshed.Name)
	}

	items, err := local.GetLocalPricelistItems(refreshed.ID)
	if err != nil {
		t.Fatalf("load refreshed local items: %v", err)
	}
	if len(items) != 1 {
		t.Fatalf("expected 1 local item after refresh, got %d", len(items))
	}
	if items[0].LotName != "CPU_A" {
		t.Fatalf("expected refreshed item CPU_A, got %q", items[0].LotName)
	}
}

func newLocalDBForUpsertTest(t *testing.T) *localdb.LocalDB {
	t.Helper()
	localPath := filepath.Join(t.TempDir(), "local.db")
	local, err := localdb.New(localPath)
	if err != nil {
		t.Fatalf("init local db: %v", err)
	}
	t.Cleanup(func() { _ = local.Close() })
	return local
}

func newServerDBForUpsertTest(t *testing.T) *gorm.DB {
	t.Helper()
	serverPath := filepath.Join(t.TempDir(), "server.db")
	db, err := gorm.Open(sqlite.Open(serverPath), &gorm.Config{})
	if err != nil {
		t.Fatalf("open server sqlite: %v", err)
	}
	return db
}
