package worker

import (
	"context"
	"encoding/json"
	"log"
	"strings"
	"time"

	"rijig/config"
	"rijig/dto"
	"rijig/internal/repositories"
	"rijig/internal/services"
	"rijig/model"
)

type CartWorker struct {
	cartService services.CartService
	cartRepo    repositories.CartRepository
	trashRepo   repositories.TrashRepository
}

func NewCartWorker(cartService services.CartService, cartRepo repositories.CartRepository, trashRepo repositories.TrashRepository) *CartWorker {
	return &CartWorker{
		cartService: cartService,
		cartRepo:    cartRepo,
		trashRepo:   trashRepo,
	}
}

func (w *CartWorker) AutoCommitExpiringCarts() error {
	ctx := context.Background()
	threshold := 1 * time.Minute

	keys, err := services.GetExpiringCartKeys(ctx, threshold)
	if err != nil {
		return err
	}

	if len(keys) == 0 {
		return nil
	}

	log.Printf("[CART-WORKER] Found %d carts expiring within 1 minute", len(keys))

	successCount := 0
	for _, key := range keys {
		userID := w.extractUserIDFromKey(key)
		if userID == "" {
			log.Printf("[CART-WORKER] Invalid key format: %s", key)
			continue
		}

		hasCart, err := w.cartRepo.HasExistingCart(ctx, userID)
		if err != nil {
			log.Printf("[CART-WORKER] Error checking existing cart for user %s: %v", userID, err)
			continue
		}

		if hasCart {

			if err := services.DeleteCartFromRedis(ctx, userID); err != nil {
				log.Printf("[CART-WORKER] Failed to delete Redis cache for user %s: %v", userID, err)
			} else {
				log.Printf("[CART-WORKER] Deleted Redis cache for user %s (already has DB cart)", userID)
			}
			continue
		}

		cartData, err := w.getCartFromRedis(ctx, key)
		if err != nil {
			log.Printf("[CART-WORKER] Failed to get cart data for key %s: %v", key, err)
			continue
		}

		if err := w.commitCartToDB(ctx, userID, cartData); err != nil {
			log.Printf("[CART-WORKER] Failed to commit cart for user %s: %v", userID, err)
			continue
		}

		if err := services.DeleteCartFromRedis(ctx, userID); err != nil {
			log.Printf("[CART-WORKER] Warning: Failed to delete Redis key after commit for user %s: %v", userID, err)
		}

		successCount++
		log.Printf("[CART-WORKER] Successfully auto-committed cart for user %s", userID)
	}

	log.Printf("[CART-WORKER] Auto-commit completed: %d successful commits", successCount)
	return nil
}

func (w *CartWorker) extractUserIDFromKey(key string) string {
	parts := strings.Split(key, ":")
	if len(parts) >= 2 {
		return parts[len(parts)-1]
	}
	return ""
}

func (w *CartWorker) getCartFromRedis(ctx context.Context, key string) (*dto.RequestCartDTO, error) {
	val, err := config.RedisClient.Get(ctx, key).Result()
	if err != nil {
		return nil, err
	}

	var cart dto.RequestCartDTO
	if err := json.Unmarshal([]byte(val), &cart); err != nil {
		return nil, err
	}

	return &cart, nil
}

func (w *CartWorker) commitCartToDB(ctx context.Context, userID string, cartData *dto.RequestCartDTO) error {
	if len(cartData.CartItems) == 0 {
		return nil
	}

	totalAmount := 0.0
	totalPrice := 0.0
	var cartItems []model.CartItem

	for _, item := range cartData.CartItems {
		if item.Amount <= 0 {
			continue
		}

		trash, err := w.trashRepo.GetTrashCategoryByID(ctx, item.TrashID)
		if err != nil {
			log.Printf("[CART-WORKER] Warning: Skipping invalid trash category %s", item.TrashID)
			continue
		}

		subtotal := item.Amount * trash.EstimatedPrice
		totalAmount += item.Amount
		totalPrice += subtotal

		cartItems = append(cartItems, model.CartItem{
			TrashCategoryID:        item.TrashID,
			Amount:                 item.Amount,
			SubTotalEstimatedPrice: subtotal,
		})
	}

	if len(cartItems) == 0 {
		return nil
	}

	newCart := &model.Cart{
		UserID:              userID,
		TotalAmount:         totalAmount,
		EstimatedTotalPrice: totalPrice,
		CartItems:           cartItems,
	}

	return w.cartRepo.CreateCartWithItems(ctx, newCart)
}
