package repository_test

import (
	"system-altrak/internal/domain"
	"system-altrak/internal/modules/auth"
	"system-altrak/internal/repository"
	"testing"

	"github.com/glebarez/sqlite"
	"github.com/stretchr/testify/assert"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
)

func setupTestDB() *gorm.DB {
	db, _ := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{
		Logger: logger.Default.LogMode(logger.Silent),
	})
	db.AutoMigrate(
		&domain.User{},
		&domain.OperationalRecord{},
		&domain.Memorandum{},
		&domain.SerialSequence{},
		&domain.RefreshToken{},
	)
	return db
}

func TestRepository_UserOperations(t *testing.T) {
	db := setupTestDB()
	repo := auth.NewRepository(db)

	t.Run("Save and Get Refresh Token", func(t *testing.T) {
		token := &domain.RefreshToken{
			UserID:    1,
			TokenHash: "hash123",
			Revoked:   false,
		}
		err := repo.SaveRefreshToken(token)
		assert.NoError(t, err)

		retrieved, err := repo.GetRefreshToken("hash123")
		assert.NoError(t, err)
		assert.Equal(t, uint(1), retrieved.UserID)
	})
}

func TestRepository_OperationalRecordOperations(t *testing.T) {
	db := setupTestDB()
	repo := repository.NewRepository(db)

	t.Run("Upsert OperationalRecord", func(t *testing.T) {
		record := &domain.OperationalRecord{
			PsoNo:        "PSO-001",
			CustomerName: "Test Customer",
			Amount:       1000000,
		}
		err := repo.UpsertOperationalRecord(record)
		assert.NoError(t, err)

		retrieved, err := repo.GetOperationalRecordByPsoNo("PSO-001")
		assert.NoError(t, err)
		assert.Equal(t, "Test Customer", retrieved.CustomerName)
	})
}

func TestRepository_MemorandumOperations(t *testing.T) {
	db := setupTestDB()
	repo := repository.NewRepository(db)

	t.Run("Get Next Serial Sequence", func(t *testing.T) {
		// First call should create sequence 1
		seq, err := repo.GetNextSequence("MEMO", 2024, 2)
		assert.NoError(t, err)
		assert.Equal(t, 1, seq)

		// Second call should return 2
		seq2, err := repo.GetNextSequence("MEMO", 2024, 2)
		assert.NoError(t, err)
		assert.Equal(t, 2, seq2)
	})
}

func TestRepository_Transaction(t *testing.T) {
	db := setupTestDB()
	repo := repository.NewRepository(db)

	t.Run("Transaction Rollback", func(t *testing.T) {
		err := repo.WithTransaction(func(txRepo *repository.Repository) error {
			record := &domain.OperationalRecord{PsoNo: "PSO-TX", CustomerName: "TX"}
			txRepo.UpsertOperationalRecord(record)
			return assert.AnError // Force rollback
		})
		assert.Error(t, err)

		_, err = repo.GetOperationalRecordByPsoNo("PSO-TX")
		assert.Error(t, err) // Should not exist
	})
}
