package repositories

import (
	"context"
	"errors"
	"fmt"

	"rijig/config"
	"rijig/model"

	"gorm.io/gorm"
)

type CartRepository interface {
	FindOrCreateCart(ctx context.Context, userID string) (*model.Cart, error)
	AddOrUpdateCartItem(ctx context.Context, cartID, trashCategoryID string, amount float64, estimatedPrice float64) error
	DeleteCartItem(ctx context.Context, cartID, trashCategoryID string) error
	GetCartByUser(ctx context.Context, userID string) (*model.Cart, error)
	UpdateCartTotals(ctx context.Context, cartID string) error
	DeleteCart(ctx context.Context, userID string) error
	// New method for batch cart creation
	CreateCartWithItems(ctx context.Context, cart *model.Cart) error
	// Check if user already has a cart
	HasExistingCart(ctx context.Context, userID string) (bool, error)
}

type cartRepository struct{}

func NewCartRepository() CartRepository {
	return &cartRepository{}
}

func (r *cartRepository) FindOrCreateCart(ctx context.Context, userID string) (*model.Cart, error) {
	var cart model.Cart
	db := config.DB.WithContext(ctx)

	err := db.
		Preload("CartItems.TrashCategory").
		Where("user_id = ?", userID).
		First(&cart).Error

	if err == nil {
		return &cart, nil
	}

	if errors.Is(err, gorm.ErrRecordNotFound) {
		newCart := model.Cart{
			UserID:              userID,
			TotalAmount:         0,
			EstimatedTotalPrice: 0,
		}
		if err := db.Create(&newCart).Error; err != nil {
			return nil, err
		}
		return &newCart, nil
	}

	return nil, err
}

func (r *cartRepository) AddOrUpdateCartItem(ctx context.Context, cartID, trashCategoryID string, amount float64, estimatedPrice float64) error {
	db := config.DB.WithContext(ctx)

	var item model.CartItem
	err := db.
		Where("cart_id = ? AND trash_category_id = ?", cartID, trashCategoryID).
		First(&item).Error

	if errors.Is(err, gorm.ErrRecordNotFound) {
		newItem := model.CartItem{
			CartID:                 cartID,
			TrashCategoryID:        trashCategoryID,
			Amount:                 amount,
			SubTotalEstimatedPrice: amount * estimatedPrice,
		}
		return db.Create(&newItem).Error
	}

	if err != nil {
		return err
	}

	item.Amount = amount
	item.SubTotalEstimatedPrice = amount * estimatedPrice
	return db.Save(&item).Error
}

func (r *cartRepository) DeleteCartItem(ctx context.Context, cartID, trashCategoryID string) error {
	db := config.DB.WithContext(ctx)
	return db.Where("cart_id = ? AND trash_category_id = ?", cartID, trashCategoryID).
		Delete(&model.CartItem{}).Error
}

func (r *cartRepository) GetCartByUser(ctx context.Context, userID string) (*model.Cart, error) {
	var cart model.Cart
	db := config.DB.WithContext(ctx)

	err := db.
		Preload("CartItems.TrashCategory").
		Where("user_id = ?", userID).
		First(&cart).Error

	if err != nil {
		return nil, err
	}
	return &cart, nil
}

func (r *cartRepository) UpdateCartTotals(ctx context.Context, cartID string) error {
	db := config.DB.WithContext(ctx)

	var items []model.CartItem
	if err := db.Where("cart_id = ?", cartID).Find(&items).Error; err != nil {
		return err
	}

	var totalAmount float64
	var totalPrice float64

	for _, item := range items {
		totalAmount += item.Amount
		totalPrice += item.SubTotalEstimatedPrice
	}

	return db.Model(&model.Cart{}).
		Where("id = ?", cartID).
		Updates(map[string]interface{}{
			"total_amount":          totalAmount,
			"estimated_total_price": totalPrice,
		}).Error
}

func (r *cartRepository) DeleteCart(ctx context.Context, userID string) error {
	db := config.DB.WithContext(ctx)
	var cart model.Cart
	if err := db.Where("user_id = ?", userID).First(&cart).Error; err != nil {
		return err
	}
	return db.Delete(&cart).Error
}

// New method for batch cart creation with transaction
func (r *cartRepository) CreateCartWithItems(ctx context.Context, cart *model.Cart) error {
	db := config.DB.WithContext(ctx)
	
	// Use transaction to ensure data consistency
	return db.Transaction(func(tx *gorm.DB) error {
		if err := tx.Create(cart).Error; err != nil {
			return fmt.Errorf("failed to create cart: %w", err)
		}
		return nil
	})
}

// Check if user already has a cart
func (r *cartRepository) HasExistingCart(ctx context.Context, userID string) (bool, error) {
	db := config.DB.WithContext(ctx)
	
	var count int64
	err := db.Model(&model.Cart{}).Where("user_id = ?", userID).Count(&count).Error
	if err != nil {
		return false, err
	}
	
	return count > 0, nil
}
