package repository

import (
	"context"
	"time"

	entity "gitlab.com/mbugroup/lti-api.git/internal/entities"
	"gorm.io/gorm"
)

type StockAllocationRepository interface {
	BaseRepository[entity.StockAllocation]
	FindActiveByUsable(ctx context.Context, usableType string, usableID uint, modifier func(*gorm.DB) *gorm.DB) ([]entity.StockAllocation, error)
	ReleaseByUsable(ctx context.Context, usableType string, usableID uint, note *string, modifier func(*gorm.DB) *gorm.DB) error
}

type StockAllocationRepositoryImpl struct {
	*BaseRepositoryImpl[entity.StockAllocation]
}

func NewStockAllocationRepository(db *gorm.DB) StockAllocationRepository {
	return &StockAllocationRepositoryImpl{
		BaseRepositoryImpl: NewBaseRepository[entity.StockAllocation](db),
	}
}

func (r *StockAllocationRepositoryImpl) FindActiveByUsable(
	ctx context.Context,
	usableType string,
	usableID uint,
	modifier func(*gorm.DB) *gorm.DB,
) ([]entity.StockAllocation, error) {
	var allocations []entity.StockAllocation

	q := r.DB().WithContext(ctx).
		Where("usable_type = ? AND usable_id = ? AND status = ? AND allocation_purpose = ?", usableType, usableID, entity.StockAllocationStatusActive, entity.StockAllocationPurposeConsume)

	if modifier != nil {
		q = modifier(q)
	}

	if err := q.Order("created_at ASC").Find(&allocations).Error; err != nil {
		return nil, err
	}

	return allocations, nil
}

func (r *StockAllocationRepositoryImpl) ReleaseByUsable(
	ctx context.Context,
	usableType string,
	usableID uint,
	note *string,
	modifier func(*gorm.DB) *gorm.DB,
) error {
	now := time.Now()

	updates := map[string]any{
		"status":      entity.StockAllocationStatusReleased,
		"released_at": now,
	}
	if note != nil {
		updates["note"] = *note
	}

	baseDB := r.DB()
	if modifier != nil {
		baseDB = modifier(baseDB)
	}

	q := baseDB.WithContext(ctx).
		Model(&entity.StockAllocation{}).
		Where("usable_type = ? AND usable_id = ? AND status = ? AND allocation_purpose = ?", usableType, usableID, entity.StockAllocationStatusActive, entity.StockAllocationPurposeConsume)

	return q.Updates(updates).Error
}
