package repository

import (
	"context"

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

type ProjectChickinRepository interface {
	repository.BaseRepository[entity.ProjectChickin]
	GetFirstByProjectFlockID(ctx context.Context, projectFlockID uint) (*entity.ProjectChickin, error)
	GetByProjectFlockID(ctx context.Context, projectFlockID uint) ([]entity.ProjectChickin, error)
	GetByProjectFlockKandangID(ctx context.Context, projectFlockKandangID uint) ([]entity.ProjectChickin, error)
	GetPendingByProjectFlockKandangID(ctx context.Context, projectFlockKandangID uint) ([]entity.ProjectChickin, error)
	GetTotalPendingUsageQtyByProjectFlockKandangID(ctx context.Context, projectFlockKandangID uint) (float64, error)
	GetTotalChickinQtyByProjectFlockID(ctx context.Context, projectFlockID uint) (float64, error)
	GetByProjectFlockKandangIDForUpdate(ctx context.Context, projectFlockKandangID uint) ([]entity.ProjectChickin, error)
	UpdateUsageFields(ctx context.Context, tx *gorm.DB, chickinID uint, usageQty, pendingUsageQty float64) error
}

type ChickinRepositoryImpl struct {
	*repository.BaseRepositoryImpl[entity.ProjectChickin]
	db *gorm.DB
}

func NewChickinRepository(db *gorm.DB) ProjectChickinRepository {
	return &ChickinRepositoryImpl{
		BaseRepositoryImpl: repository.NewBaseRepository[entity.ProjectChickin](db),
		db:                 db,
	}
}

func (r *ChickinRepositoryImpl) GetFirstByProjectFlockID(ctx context.Context, projectFlockID uint) (*entity.ProjectChickin, error) {
	var chickin entity.ProjectChickin
	err := r.db.WithContext(ctx).
		Where("project_floc_id = ?", projectFlockID).
		Where("deleted_at IS NULL").
		First(&chickin).Error
	if err != nil {
		return nil, err
	}
	return &chickin, nil
}

func (r *ChickinRepositoryImpl) GetByProjectFlockID(ctx context.Context, projectFlockID uint) ([]entity.ProjectChickin, error) {
	var chickins []entity.ProjectChickin
	err := r.db.WithContext(ctx).
		Joins("JOIN project_flock_kandangs ON project_flock_kandangs.id = project_chickins.project_flock_kandang_id").
		Where("project_flock_kandangs.project_flock_id = ?", projectFlockID).
		Order("project_chickins.created_at DESC").
		Find(&chickins).Error
	return chickins, err
}

func (r *ChickinRepositoryImpl) GetByProjectFlockKandangID(ctx context.Context, projectFlockKandangID uint) ([]entity.ProjectChickin, error) {
	var chickins []entity.ProjectChickin
	err := r.db.WithContext(ctx).
		Where("project_flock_kandang_id = ?", projectFlockKandangID).
		Order("created_at DESC").
		Find(&chickins).Error
	if err != nil {
		return nil, err
	}
	return chickins, nil
}

// GetByProjectFlockKandangIDForUpdate locks chickin rows to prevent race condition
func (r *ChickinRepositoryImpl) GetByProjectFlockKandangIDForUpdate(ctx context.Context, projectFlockKandangID uint) ([]entity.ProjectChickin, error) {
	var chickins []entity.ProjectChickin
	// CRITICAL: Use FOR UPDATE to lock rows and prevent concurrent chickin requests
	// This ensures that simultaneous requests wait for each other and read consistent pending_qty
	err := r.db.WithContext(ctx).
		Raw(`
			SELECT * FROM project_chickins
			WHERE project_flock_kandang_id = ?
			AND deleted_at IS NULL
			ORDER BY created_at DESC
			FOR UPDATE
		`, projectFlockKandangID).
		Scan(&chickins).Error
	if err != nil {
		return nil, err
	}
	return chickins, nil
}

func (r *ChickinRepositoryImpl) GetPendingByProjectFlockKandangID(ctx context.Context, projectFlockKandangID uint) ([]entity.ProjectChickin, error) {
	var chickins []entity.ProjectChickin
	err := r.db.WithContext(ctx).
		Where("project_flock_kandang_id = ?", projectFlockKandangID).
		Where("usage_qty = 0").
		Where("pending_usage_qty > 0").
		Order("created_at DESC").
		Find(&chickins).Error
	if err != nil {
		return nil, err
	}
	return chickins, nil
}

func (r *ChickinRepositoryImpl) GetTotalPendingUsageQtyByProjectFlockKandangID(ctx context.Context, projectFlockKandangID uint) (float64, error) {
	var total float64
	err := r.db.WithContext(ctx).
		Model(&entity.ProjectChickin{}).
		Where("project_flock_kandang_id = ?", projectFlockKandangID).
		Where("pending_usage_qty > 0").
		Select("COALESCE(SUM(pending_usage_qty), 0)").
		Row().Scan(&total)
	if err != nil {
		return 0, err
	}
	return total, nil
}

func (r *ChickinRepositoryImpl) GetTotalChickinQtyByProjectFlockID(ctx context.Context, projectFlockID uint) (float64, error) {
	var result float64
	err := r.db.WithContext(ctx).
		Table("project_chickins").
		Select("COALESCE(SUM(project_chickins.usage_qty), 0)").
		Joins("JOIN project_flock_kandangs ON project_flock_kandangs.id = project_chickins.project_flock_kandang_id").
		Where("project_flock_kandangs.project_flock_id = ?", projectFlockID).
		Scan(&result).Error
	return result, err
}

func (r *ChickinRepositoryImpl) UpdateUsageFields(ctx context.Context, tx *gorm.DB, chickinID uint, usageQty, pendingUsageQty float64) error {
	return tx.WithContext(ctx).
		Model(&entity.ProjectChickin{}).
		Where("id = ?", chickinID).
		Updates(map[string]interface{}{
			"usage_qty":         usageQty,
			"pending_usage_qty": pendingUsageQty,
		}).Error
}
