package service

import (
	"apskel-pos-be/internal/entities"
	"apskel-pos-be/internal/repository"
	"context"
	"time"

	"github.com/google/uuid"
)

type InventoryMovementService interface {
	CreateIngredientMovement(ctx context.Context, ingredientID, organizationID, outletID, userID uuid.UUID, movementType entities.InventoryMovementType, quantity float64, unitCost float64, reason string, referenceType *entities.InventoryMovementReferenceType, referenceID *uuid.UUID) error
	CreateProductMovement(ctx context.Context, productID, organizationID, outletID, userID uuid.UUID, movementType entities.InventoryMovementType, quantity float64, unitCost float64, reason string, referenceType *entities.InventoryMovementReferenceType, referenceID *uuid.UUID) error
}

type InventoryMovementServiceImpl struct {
	inventoryMovementRepo repository.InventoryMovementRepository
	ingredientRepo        *repository.IngredientRepository
}

func NewInventoryMovementService(inventoryMovementRepo repository.InventoryMovementRepository, ingredientRepo *repository.IngredientRepository) InventoryMovementService {
	return &InventoryMovementServiceImpl{
		inventoryMovementRepo: inventoryMovementRepo,
		ingredientRepo:        ingredientRepo,
	}
}

func (s *InventoryMovementServiceImpl) CreateIngredientMovement(ctx context.Context, ingredientID, organizationID, outletID, userID uuid.UUID, movementType entities.InventoryMovementType, quantity float64, unitCost float64, reason string, referenceType *entities.InventoryMovementReferenceType, referenceID *uuid.UUID) error {
	ingredient, err := s.ingredientRepo.GetByID(ctx, ingredientID, organizationID)
	if err != nil {
		return err
	}

	previousQuantity := ingredient.Stock
	newQuantity := previousQuantity + quantity

	movement := &entities.InventoryMovement{
		ID:               uuid.New(),
		OrganizationID:   organizationID,
		OutletID:         outletID,
		ItemID:           ingredientID,
		ItemType:         "INGREDIENT",
		MovementType:     movementType,
		Quantity:         quantity,
		PreviousQuantity: previousQuantity,
		NewQuantity:      newQuantity,
		UnitCost:         unitCost,
		TotalCost:        unitCost * quantity,
		ReferenceType:    referenceType,
		ReferenceID:      referenceID,
		UserID:           userID,
		Reason:           &reason,
		CreatedAt:        time.Now(),
	}

	err = s.inventoryMovementRepo.Create(ctx, movement)
	if err != nil {
		return err
	}

	err = s.ingredientRepo.UpdateStock(ctx, ingredientID, quantity, organizationID)
	if err != nil {
		return err
	}

	return nil
}

func (s *InventoryMovementServiceImpl) CreateProductMovement(ctx context.Context, productID, organizationID, outletID, userID uuid.UUID, movementType entities.InventoryMovementType, quantity float64, unitCost float64, reason string, referenceType *entities.InventoryMovementReferenceType, referenceID *uuid.UUID) error {
	movement := &entities.InventoryMovement{
		ID:               uuid.New(),
		OrganizationID:   organizationID,
		OutletID:         outletID,
		ItemID:           productID,
		ItemType:         "PRODUCT",
		MovementType:     movementType,
		Quantity:         quantity,
		PreviousQuantity: 0, // TODO This would be fetched from product inventory
		NewQuantity:      0, // TODO This would be calculated
		UnitCost:         unitCost,
		TotalCost:        unitCost * quantity,
		ReferenceType:    referenceType,
		ReferenceID:      referenceID,
		UserID:           userID,
		Reason:           &reason,
		CreatedAt:        time.Now(),
	}

	err := s.inventoryMovementRepo.Create(ctx, movement)
	if err != nil {
		return err
	}

	return nil
}
