package repository

import (
	"context"
	"errors"
	"fmt"
	"time"

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

type HppV2ProjectFlockKandangContext struct {
	ProjectFlockKandangID uint
	ProjectFlockID        uint
	ProjectFlockCategory  string
	KandangID             uint
	KandangName           string
	LocationID            uint
	HouseType             string
}

type HppV2UsageCostRow struct {
	StockableType     string
	StockableID       uint
	SourceProductID   uint
	SourceProductName string
	Qty               float64
	UnitPrice         float64
	TotalCost         float64
	FirstUsedAt       time.Time
	LastUsedAt        time.Time
}

type HppV2AdjustmentCostRow struct {
	AdjustmentID          uint
	ProjectFlockKandangID *uint
	ProductWarehouseID    uint
	ProductID             uint
	ProductName           string
	WarehouseID           uint
	WarehouseType         string
	Qty                   float64
	Price                 float64
	GrandTotal            float64
	CreatedAt             time.Time
}

type HppV2ExpenseCostRow struct {
	ExpenseRealizationID uint
	ExpenseNonstockID    uint
	ExpenseID            uint
	NonstockID           uint
	NonstockName         string
	Qty                  float64
	Price                float64
	TotalCost            float64
	RealizationDate      time.Time
}

type HppV2ChickinCostRow struct {
	ProjectChickinID      uint
	ProjectFlockKandangID uint
	ChickInDate           time.Time
	StockableType         string
	StockableID           uint
	SourceProductID       uint
	SourceProductName     string
	Qty                   float64
	UnitPrice             float64
	TotalCost             float64
}

type HppV2LatestTransferInputRow struct {
	ProjectFlockKandangID uint
	SourceProjectFlockID  uint
	TransferDate          time.Time
	TransferQty           float64
	TransferID            uint
}

type HppV2ManualDepreciationInputRow struct {
	ID             uint
	ProjectFlockID uint
	TotalCost      float64
	CutoverDate    time.Time
	Note           *string
}

type HppV2FarmDepreciationSnapshotRow struct {
	ID                           uint
	ProjectFlockID               uint
	PeriodDate                   time.Time
	DepreciationPercentEffective float64
	DepreciationValue            float64
	PulletCostDayNTotal          float64
}

type HppV2CostRepository interface {
	GetProjectFlockKandangContext(ctx context.Context, projectFlockKandangId uint) (*HppV2ProjectFlockKandangContext, error)
	GetProjectFlockKandangIDs(ctx context.Context, projectFlockId uint) ([]uint, error)
	GetLatestTransferInputByProjectFlockKandangID(ctx context.Context, projectFlockKandangId uint, period time.Time) (*HppV2LatestTransferInputRow, error)
	GetManualDepreciationInputByProjectFlockID(ctx context.Context, projectFlockID uint) (*HppV2ManualDepreciationInputRow, error)
	GetRecordingStockRoutingAdjustmentCostByProjectFlockID(ctx context.Context, projectFlockID uint, periodDate time.Time) (float64, error)
	GetFarmDepreciationSnapshotByProjectFlockIDAndPeriod(ctx context.Context, projectFlockID uint, periodDate time.Time) (*HppV2FarmDepreciationSnapshotRow, error)
	GetEarliestChickInDateByProjectFlockID(ctx context.Context, projectFlockID uint) (*time.Time, error)
	GetDepreciationPercents(ctx context.Context, houseTypes []string, maxDay int) (map[string]map[int]float64, error)
	ListUsageCostRowsByProductFlags(ctx context.Context, projectFlockKandangIDs []uint, flagNames []string, date *time.Time) ([]HppV2UsageCostRow, error)
	ListAdjustmentCostRowsByProductFlags(ctx context.Context, projectFlockKandangIDs []uint, flagNames []string, date *time.Time) ([]HppV2AdjustmentCostRow, error)
	ListExpenseRealizationRowsByProjectFlockKandangIDs(ctx context.Context, projectFlockKandangIDs []uint, date *time.Time, ekspedisi bool) ([]HppV2ExpenseCostRow, error)
	ListExpenseRealizationRowsByProjectFlockID(ctx context.Context, projectFlockID uint, date *time.Time, ekspedisi bool) ([]HppV2ExpenseCostRow, error)
	ListChickinCostRowsByProductFlags(ctx context.Context, projectFlockKandangIDs []uint, flagNames []string, date *time.Time, excludeTransferToLaying bool) ([]HppV2ChickinCostRow, error)
	GetFeedUsageCost(ctx context.Context, projectFlockKandangIDs []uint, date *time.Time) (float64, error)
	GetTotalPopulation(ctx context.Context, projectFlockKandangIDs []uint) (float64, error)
	GetEggProduksiPiecesAndWeightKgByProjectFlockKandangIds(ctx context.Context, projectFlockKandangIDs []uint, date *time.Time) (float64, float64, error)
	GetEggProduksiBreakdownByProjectFlockKandangIds(ctx context.Context, projectFlockKandangIDs []uint, date *time.Time) (recordingQty, recordingWeight, adjustmentQty, adjustmentWeight float64, err error)
	GetEggTerjualPiecesAndWeightKgByProjectFlockKandangIds(ctx context.Context, projectFlockKandangIDs []uint, startDate *time.Time, endDate *time.Time) (float64, float64, error)
	GetTransferSourceSummary(ctx context.Context, projectFlockKandangId uint) (uint, float64, error)
}

type HppV2RepositoryImpl struct {
	db *gorm.DB
}

func NewHppV2CostRepository(db *gorm.DB) HppV2CostRepository {
	return &HppV2RepositoryImpl{db: db}
}

func (r *HppV2RepositoryImpl) GetProjectFlockKandangContext(ctx context.Context, projectFlockKandangId uint) (*HppV2ProjectFlockKandangContext, error) {
	var row HppV2ProjectFlockKandangContext
	err := r.db.WithContext(ctx).
		Table("project_flock_kandangs AS pfk").
		Select(`
			pfk.id AS project_flock_kandang_id,
			pf.id AS project_flock_id,
			pf.category AS project_flock_category,
			k.id AS kandang_id,
			k.name AS kandang_name,
			k.location_id AS location_id,
			k.house_type::text AS house_type
		`).
		Joins("JOIN project_flocks AS pf ON pf.id = pfk.project_flock_id").
		Joins("JOIN kandangs AS k ON k.id = pfk.kandang_id").
		Where("pfk.id = ?", projectFlockKandangId).
		Scan(&row).Error
	if err != nil {
		return nil, err
	}
	if row.ProjectFlockKandangID == 0 {
		return nil, gorm.ErrRecordNotFound
	}

	return &row, nil
}

func (r *HppV2RepositoryImpl) GetProjectFlockKandangIDs(ctx context.Context, projectFlockId uint) ([]uint, error) {
	var ids []uint
	err := r.db.WithContext(ctx).
		Table("project_flock_kandangs").
		Select("id").
		Where("project_flock_id = ?", projectFlockId).
		Scan(&ids).Error
	if err != nil {
		return nil, err
	}

	return ids, nil
}

func (r *HppV2RepositoryImpl) GetLatestTransferInputByProjectFlockKandangID(
	ctx context.Context,
	projectFlockKandangId uint,
	period time.Time,
) (*HppV2LatestTransferInputRow, error) {
	var row HppV2LatestTransferInputRow
	query := `
WITH latest_transfer_approval AS (
	SELECT a.approvable_id, a.action
	FROM approvals a
	JOIN (
		SELECT approvable_id, MAX(action_at) AS latest_action_at
		FROM approvals
		WHERE approvable_type = @approval_type
		GROUP BY approvable_id
	) la
		ON la.approvable_id = a.approvable_id
		AND la.latest_action_at = a.action_at
	WHERE a.approvable_type = @approval_type
),
approved_transfers AS (
	SELECT
		lt.id,
		lt.from_project_flock_id,
		COALESCE(DATE(lt.effective_move_date), DATE(lt.economic_cutoff_date), DATE(lt.transfer_date)) AS effective_date
	FROM laying_transfers lt
	JOIN latest_transfer_approval lta ON lta.approvable_id = lt.id
	WHERE lt.deleted_at IS NULL
	  AND lt.executed_at IS NOT NULL
	  AND lta.action = 'APPROVED'
)
SELECT
	ltt.target_project_flock_kandang_id AS project_flock_kandang_id,
	at.from_project_flock_id AS source_project_flock_id,
	at.effective_date AS transfer_date,
	ltt.total_qty AS transfer_qty,
	at.id AS transfer_id
FROM laying_transfer_targets ltt
JOIN approved_transfers at ON at.id = ltt.laying_transfer_id
WHERE ltt.deleted_at IS NULL
  AND ltt.target_project_flock_kandang_id = @project_flock_kandang_id
  AND at.effective_date <= DATE(@period_date)
ORDER BY at.effective_date DESC, at.id DESC
LIMIT 1
`

	err := r.db.WithContext(ctx).Raw(query, map[string]any{
		"approval_type":            utils.ApprovalWorkflowTransferToLaying.String(),
		"project_flock_kandang_id": projectFlockKandangId,
		"period_date":              period,
	}).Scan(&row).Error
	if err != nil {
		return nil, err
	}
	if row.TransferID == 0 {
		return nil, nil
	}

	return &row, nil
}

func (r *HppV2RepositoryImpl) GetManualDepreciationInputByProjectFlockID(
	ctx context.Context,
	projectFlockID uint,
) (*HppV2ManualDepreciationInputRow, error) {
	var row HppV2ManualDepreciationInputRow
	err := r.db.WithContext(ctx).
		Table("farm_depreciation_manual_inputs").
		Select("id, project_flock_id, total_cost, cutover_date, note").
		Where("project_flock_id = ?", projectFlockID).
		Limit(1).
		Take(&row).Error
	if errors.Is(err, gorm.ErrRecordNotFound) {
		return nil, nil
	}
	if err != nil {
		return nil, err
	}

	return &row, nil
}

func (r *HppV2RepositoryImpl) GetRecordingStockRoutingAdjustmentCostByProjectFlockID(
	ctx context.Context,
	projectFlockID uint,
	periodDate time.Time,
) (float64, error) {
	if projectFlockID == 0 || periodDate.IsZero() {
		return 0, nil
	}

	flags := []utils.FlagType{
		utils.FlagPakan,
		utils.FlagOVK,
		utils.FlagObat,
		utils.FlagVitamin,
		utils.FlagKimia,
	}
	transferExistsCondition := `
		EXISTS (
			SELECT 1
			FROM laying_transfer_targets AS ltt
			JOIN laying_transfers AS lt ON lt.id = ltt.laying_transfer_id
			WHERE ltt.deleted_at IS NULL
				AND lt.deleted_at IS NULL
				AND lt.executed_at IS NOT NULL
				AND ltt.target_project_flock_kandang_id = r.project_flock_kandangs_id
				AND COALESCE(DATE(lt.effective_move_date), DATE(lt.economic_cutoff_date), DATE(lt.transfer_date)) <= DATE(?)
				AND (
					SELECT a.action
					FROM approvals a
					WHERE a.approvable_type = ?
						AND a.approvable_id = lt.id
					ORDER BY a.id DESC
					LIMIT 1
				) = ?
		)
	`

	var total float64
	err := r.db.WithContext(ctx).
		Table("recording_stocks AS rs").
		Select("COALESCE(SUM(sa.qty * COALESCE(pi.price, 0)), 0)").
		Joins("JOIN recordings AS r ON r.id = rs.recording_id AND r.deleted_at IS NULL").
		Joins("JOIN project_flock_kandangs AS pfk_rec ON pfk_rec.id = r.project_flock_kandangs_id").
		Joins("JOIN product_warehouses AS pw ON pw.id = rs.product_warehouse_id").
		Joins(
			"JOIN stock_allocations AS sa ON sa.usable_type = ? AND sa.usable_id = rs.id AND sa.stockable_type = ? AND sa.status = ? AND sa.allocation_purpose = ?",
			fifo.UsableKeyRecordingStock.String(),
			fifo.StockableKeyPurchaseItems.String(),
			entity.StockAllocationStatusActive,
			entity.StockAllocationPurposeConsume,
		).
		Joins("JOIN purchase_items AS pi ON pi.id = sa.stockable_id").
		Where("pfk_rec.project_flock_id = ?", projectFlockID).
		Where("DATE(r.record_datetime) <= DATE(?)", periodDate).
		Where(
			fmt.Sprintf(
				"((%s) AND rs.project_flock_kandang_id IS NOT NULL AND rs.project_flock_kandang_id <> r.project_flock_kandangs_id) OR (NOT (%s) AND rs.project_flock_kandang_id IS NULL)",
				transferExistsCondition,
				transferExistsCondition,
			),
			periodDate,
			string(utils.ApprovalWorkflowTransferToLaying),
			entity.ApprovalActionApproved,
			periodDate,
			string(utils.ApprovalWorkflowTransferToLaying),
			entity.ApprovalActionApproved,
		).
		Where("EXISTS (SELECT 1 FROM flags f WHERE f.flagable_id = pw.product_id AND f.flagable_type = ? AND f.name IN ?)", entity.FlagableTypeProduct, flags).
		Scan(&total).Error
	if err != nil {
		return 0, err
	}

	return total, nil
}

func (r *HppV2RepositoryImpl) GetFarmDepreciationSnapshotByProjectFlockIDAndPeriod(
	ctx context.Context,
	projectFlockID uint,
	periodDate time.Time,
) (*HppV2FarmDepreciationSnapshotRow, error) {
	var row HppV2FarmDepreciationSnapshotRow
	err := r.db.WithContext(ctx).
		Table("farm_depreciation_snapshots").
		Select("id, project_flock_id, period_date, depreciation_percent_effective, depreciation_value, pullet_cost_day_n_total").
		Where("project_flock_id = ?", projectFlockID).
		Where("period_date = DATE(?)", periodDate).
		Limit(1).
		Take(&row).Error
	if errors.Is(err, gorm.ErrRecordNotFound) {
		return nil, nil
	}
	if err != nil {
		return nil, err
	}

	return &row, nil
}

func (r *HppV2RepositoryImpl) GetEarliestChickInDateByProjectFlockID(ctx context.Context, projectFlockID uint) (*time.Time, error) {
	type row struct {
		ChickInDate *time.Time
	}

	var selected row
	err := r.db.WithContext(ctx).
		Table("project_chickins AS pc").
		Select("MIN(pc.chick_in_date) AS chick_in_date").
		Joins("JOIN project_flock_kandangs AS pfk ON pfk.id = pc.project_flock_kandang_id").
		Where("pc.deleted_at IS NULL").
		Where("pfk.project_flock_id = ?", projectFlockID).
		Scan(&selected).Error
	if err != nil {
		return nil, err
	}
	if selected.ChickInDate == nil || selected.ChickInDate.IsZero() {
		return nil, nil
	}

	return selected.ChickInDate, nil
}

func (r *HppV2RepositoryImpl) GetDepreciationPercents(
	ctx context.Context,
	houseTypes []string,
	maxDay int,
) (map[string]map[int]float64, error) {
	result := make(map[string]map[int]float64)
	if len(houseTypes) == 0 || maxDay <= 0 {
		return result, nil
	}

	type row struct {
		HouseType           string
		Day                 int
		DepreciationPercent float64
	}

	rows := make([]row, 0)
	err := r.db.WithContext(ctx).
		Table("house_depreciation_standards").
		Select("house_type::text AS house_type, day, depreciation_percent").
		Where("house_type::text IN ?", houseTypes).
		Where("day <= ?", maxDay).
		Order("house_type ASC, day ASC").
		Scan(&rows).Error
	if err != nil {
		return nil, err
	}

	for _, item := range rows {
		if _, exists := result[item.HouseType]; !exists {
			result[item.HouseType] = make(map[int]float64)
		}
		result[item.HouseType][item.Day] = item.DepreciationPercent
	}

	return result, nil
}

func (r *HppV2RepositoryImpl) ListUsageCostRowsByProductFlags(
	ctx context.Context,
	projectFlockKandangIDs []uint,
	flagNames []string,
	date *time.Time,
) ([]HppV2UsageCostRow, error) {
	if len(projectFlockKandangIDs) == 0 || len(flagNames) == 0 {
		return []HppV2UsageCostRow{}, nil
	}
	if date == nil {
		now := time.Now()
		date = &now
	}

	stockablePurchase := fifo.StockableKeyPurchaseItems.String()
	stockableAdjustment := fifo.StockableKeyAdjustmentIn.String()
	usableRecordingStock := fifo.UsableKeyRecordingStock.String()

	rows := make([]HppV2UsageCostRow, 0)
	err := r.db.WithContext(ctx).
		Table("recordings AS r").
		Select(`
			sa.stockable_type AS stockable_type,
			sa.stockable_id AS stockable_id,
			COALESCE(pi.product_id, ast_pw.product_id, 0) AS source_product_id,
			COALESCE(pi_prod.name, ast_prod.name, '') AS source_product_name,
			COALESCE(SUM(sa.qty), 0) AS qty,
			COALESCE(MAX(CASE
				WHEN sa.stockable_type = ? THEN COALESCE(pi.price, 0)
				WHEN sa.stockable_type = ? THEN COALESCE(ast.price, 0)
				ELSE 0
			END), 0) AS unit_price,
			COALESCE(SUM(sa.qty * CASE
				WHEN sa.stockable_type = ? THEN COALESCE(pi.price, 0)
				WHEN sa.stockable_type = ? THEN COALESCE(ast.price, 0)
				ELSE 0
			END), 0) AS total_cost,
			MIN(r.record_datetime) AS first_used_at,
			MAX(r.record_datetime) AS last_used_at
		`,
			stockablePurchase,
			stockableAdjustment,
			stockablePurchase,
			stockableAdjustment,
		).
		Joins("JOIN recording_stocks AS rs ON rs.recording_id = r.id").
		Joins("JOIN product_warehouses AS pw ON pw.id = rs.product_warehouse_id").
		Joins(
			"JOIN stock_allocations AS sa ON sa.usable_type = ? AND sa.usable_id = rs.id AND (sa.stockable_type = ? OR sa.stockable_type = ?) AND sa.status = ? AND sa.allocation_purpose = ?",
			usableRecordingStock,
			stockablePurchase,
			stockableAdjustment,
			entity.StockAllocationStatusActive,
			entity.StockAllocationPurposeConsume,
		).
		Joins("LEFT JOIN purchase_items AS pi ON pi.id = sa.stockable_id AND sa.stockable_type = ?", stockablePurchase).
		Joins("LEFT JOIN products AS pi_prod ON pi_prod.id = pi.product_id").
		Joins("LEFT JOIN adjustment_stocks AS ast ON ast.id = sa.stockable_id AND sa.stockable_type = ?", stockableAdjustment).
		Joins("LEFT JOIN product_warehouses AS ast_pw ON ast_pw.id = ast.product_warehouse_id").
		Joins("LEFT JOIN products AS ast_prod ON ast_prod.id = ast_pw.product_id").
		Where("rs.project_flock_kandang_id IN ?", projectFlockKandangIDs).
		Where("r.record_datetime <= ?", *date).
		Where("EXISTS (SELECT 1 FROM flags f WHERE f.flagable_id = pw.product_id AND f.flagable_type = ? AND f.name IN ?)", entity.FlagableTypeProduct, flagNames).
		Group(`
			sa.stockable_type,
			sa.stockable_id,
			COALESCE(pi.product_id, ast_pw.product_id, 0),
			COALESCE(pi_prod.name, ast_prod.name, '')
		`).
		Order("MIN(r.record_datetime) ASC, sa.stockable_type ASC, sa.stockable_id ASC").
		Scan(&rows).Error
	if err != nil {
		return nil, err
	}

	return rows, nil
}

func (r *HppV2RepositoryImpl) ListAdjustmentCostRowsByProductFlags(
	ctx context.Context,
	projectFlockKandangIDs []uint,
	flagNames []string,
	date *time.Time,
) ([]HppV2AdjustmentCostRow, error) {
	if len(projectFlockKandangIDs) == 0 || len(flagNames) == 0 {
		return []HppV2AdjustmentCostRow{}, nil
	}
	if date == nil {
		now := time.Now()
		date = &now
	}

	rows := make([]HppV2AdjustmentCostRow, 0)
	err := r.db.WithContext(ctx).
		Table("adjustment_stocks AS ast").
		Select(`
			ast.id AS adjustment_id,
			pw.project_flock_kandang_id AS project_flock_kandang_id,
			ast.product_warehouse_id AS product_warehouse_id,
			pw.product_id AS product_id,
			p.name AS product_name,
			w.id AS warehouse_id,
			w.type AS warehouse_type,
			COALESCE(ast.total_qty, 0) AS qty,
			COALESCE(ast.price, 0) AS price,
			COALESCE(ast.grand_total, 0) AS grand_total,
			ast.created_at AS created_at
		`).
		Joins("JOIN product_warehouses AS pw ON pw.id = ast.product_warehouse_id").
		Joins("JOIN products AS p ON p.id = pw.product_id").
		Joins("JOIN warehouses AS w ON w.id = pw.warehouse_id").
		Where("pw.project_flock_kandang_id IN ?", projectFlockKandangIDs).
		// Where("ast.created_at <= ?", *date).
		Where("COALESCE(ast.total_qty, 0) > 0").
		Where("EXISTS (SELECT 1 FROM flags f WHERE f.flagable_id = pw.product_id AND f.flagable_type = ? AND f.name IN ?)", entity.FlagableTypeProduct, flagNames).
		Order("ast.created_at ASC, ast.id ASC").
		Scan(&rows).Error
	if err != nil {
		return nil, err
	}

	return rows, nil
}

func (r *HppV2RepositoryImpl) ListChickinCostRowsByProductFlags(
	ctx context.Context,
	projectFlockKandangIDs []uint,
	flagNames []string,
	date *time.Time,
	excludeTransferToLaying bool,
) ([]HppV2ChickinCostRow, error) {
	if len(projectFlockKandangIDs) == 0 || len(flagNames) == 0 {
		return []HppV2ChickinCostRow{}, nil
	}
	if date == nil {
		now := time.Now()
		date = &now
	}

	stockablePurchase := fifo.StockableKeyPurchaseItems.String()
	stockableAdjustment := fifo.StockableKeyAdjustmentIn.String()
	stockableTransferIn := fifo.StockableKeyStockTransferIn.String()
	stockableTransferToLaying := fifo.StockableKeyTransferToLayingIn.String()
	usableProjectChickin := fifo.UsableKeyProjectChickin.String()
	usableStockTransferOut := fifo.UsableKeyStockTransferOut.String()
	unitPriceExpr := fmt.Sprintf(`
			CASE
				WHEN sa.stockable_type = '%s' THEN COALESCE(pi.price, 0)
				WHEN sa.stockable_type = '%s' THEN COALESCE(ast.price, 0)
				WHEN sa.stockable_type = '%s' THEN COALESCE(spi.price, sast.price, 0)
				WHEN sa.stockable_type = '%s' THEN COALESCE(tpi.price, tast.price, 0)
				ELSE 0
			END
	`, stockablePurchase, stockableAdjustment, stockableTransferIn, stockableTransferToLaying)

	rows := make([]HppV2ChickinCostRow, 0)
	query := r.db.WithContext(ctx).
		Table("project_chickins AS pc").
		Select(`
			pc.id AS project_chickin_id,
			pc.project_flock_kandang_id AS project_flock_kandang_id,
			pc.chick_in_date AS chick_in_date,
			sa.stockable_type AS stockable_type,
			sa.stockable_id AS stockable_id,
			COALESCE(
				pi.product_id,
				ast_pw.product_id,
				tpi.product_id,
				tast_pw.product_id,
				spi.product_id,
				sast_pw.product_id,
				0
			) AS source_product_id,
			COALESCE(
				pi_prod.name,
				ast_prod.name,
				tpi_prod.name,
				tast_prod.name,
				spi_prod.name,
				sast_prod.name,
				''
			) AS source_product_name,
			COALESCE(SUM(sa.qty), 0) AS qty,
			`+unitPriceExpr+` AS unit_price,
			COALESCE(SUM(sa.qty * (`+unitPriceExpr+`)), 0) AS total_cost
		`).
		Joins(
			"JOIN stock_allocations AS sa ON sa.usable_type = ? AND sa.usable_id = pc.id AND sa.status = ? AND sa.allocation_purpose = ?",
			usableProjectChickin,
			entity.StockAllocationStatusActive,
			entity.StockAllocationPurposeTraceChickin,
		).
		Joins("LEFT JOIN purchase_items AS pi ON pi.id = sa.stockable_id AND sa.stockable_type = ?", stockablePurchase).
		Joins("LEFT JOIN products AS pi_prod ON pi_prod.id = pi.product_id").
		Joins("LEFT JOIN adjustment_stocks AS ast ON ast.id = sa.stockable_id AND sa.stockable_type = ?", stockableAdjustment).
		Joins("LEFT JOIN product_warehouses AS ast_pw ON ast_pw.id = ast.product_warehouse_id").
		Joins("LEFT JOIN products AS ast_prod ON ast_prod.id = ast_pw.product_id").
		Joins(
			"LEFT JOIN stock_allocations AS tsa_transfer ON tsa_transfer.usable_type = ? AND tsa_transfer.usable_id = sa.stockable_id AND sa.stockable_type = ? AND tsa_transfer.status = ? AND tsa_transfer.allocation_purpose = ?",
			stockableTransferToLaying,
			stockableTransferToLaying,
			entity.StockAllocationStatusActive,
			entity.StockAllocationPurposeConsume,
		).
		Joins("LEFT JOIN purchase_items AS tpi ON tpi.id = tsa_transfer.stockable_id AND tsa_transfer.stockable_type = ?", stockablePurchase).
		Joins("LEFT JOIN products AS tpi_prod ON tpi_prod.id = tpi.product_id").
		Joins("LEFT JOIN adjustment_stocks AS tast ON tast.id = tsa_transfer.stockable_id AND tsa_transfer.stockable_type = ?", stockableAdjustment).
		Joins("LEFT JOIN product_warehouses AS tast_pw ON tast_pw.id = tast.product_warehouse_id").
		Joins("LEFT JOIN products AS tast_prod ON tast_prod.id = tast_pw.product_id").
		Joins(
			"LEFT JOIN stock_allocations AS tsa_stock ON tsa_stock.usable_type = ? AND tsa_stock.usable_id = sa.stockable_id AND sa.stockable_type = ? AND tsa_stock.status = ? AND tsa_stock.allocation_purpose = ?",
			usableStockTransferOut,
			stockableTransferIn,
			entity.StockAllocationStatusActive,
			entity.StockAllocationPurposeConsume,
		).
		Joins("LEFT JOIN purchase_items AS spi ON spi.id = tsa_stock.stockable_id AND tsa_stock.stockable_type = ?", stockablePurchase).
		Joins("LEFT JOIN products AS spi_prod ON spi_prod.id = spi.product_id").
		Joins("LEFT JOIN adjustment_stocks AS sast ON sast.id = tsa_stock.stockable_id AND tsa_stock.stockable_type = ?", stockableAdjustment).
		Joins("LEFT JOIN product_warehouses AS sast_pw ON sast_pw.id = sast.product_warehouse_id").
		Joins("LEFT JOIN products AS sast_prod ON sast_prod.id = sast_pw.product_id").
		Where("pc.project_flock_kandang_id IN ?", projectFlockKandangIDs).
		Where("pc.chick_in_date <= ?", *date).
		Where(`
			EXISTS (
				SELECT 1
				FROM flags f
				WHERE f.flagable_type = ?
					AND f.flagable_id = COALESCE(
						pi.product_id,
						ast_pw.product_id,
						tpi.product_id,
						tast_pw.product_id,
						spi.product_id,
						sast_pw.product_id,
						0
					)
					AND f.name IN ?
			)
		`, entity.FlagableTypeProduct, flagNames)

	if excludeTransferToLaying {
		query = query.Where("sa.stockable_type <> ?", stockableTransferToLaying)
	}

	err := query.
		Group(fmt.Sprintf(`
			pc.id,
			pc.project_flock_kandang_id,
			pc.chick_in_date,
			sa.stockable_type,
			sa.stockable_id,
			COALESCE(
				pi.product_id,
				ast_pw.product_id,
				tpi.product_id,
				tast_pw.product_id,
				spi.product_id,
				sast_pw.product_id,
				0
			),
			COALESCE(
				pi_prod.name,
				ast_prod.name,
				tpi_prod.name,
				tast_prod.name,
				spi_prod.name,
				sast_prod.name,
				''
			),
			%s
		`, unitPriceExpr)).
		Order("pc.chick_in_date ASC, pc.id ASC, sa.stockable_type ASC, sa.stockable_id ASC").
		Scan(&rows).Error
	if err != nil {
		return nil, err
	}

	return rows, nil
}

func (r *HppV2RepositoryImpl) ListExpenseRealizationRowsByProjectFlockKandangIDs(
	ctx context.Context,
	projectFlockKandangIDs []uint,
	date *time.Time,
	ekspedisi bool,
) ([]HppV2ExpenseCostRow, error) {
	if len(projectFlockKandangIDs) == 0 {
		return []HppV2ExpenseCostRow{}, nil
	}
	if date == nil {
		now := time.Now()
		date = &now
	}

	rows := make([]HppV2ExpenseCostRow, 0)
	query := r.db.WithContext(ctx).
		Table("expense_realizations AS er").
		Select(`
			er.id AS expense_realization_id,
			en.id AS expense_nonstock_id,
			e.id AS expense_id,
			COALESCE(n.id, 0) AS nonstock_id,
			COALESCE(n.name, '') AS nonstock_name,
			COALESCE(er.qty, 0) AS qty,
			COALESCE(er.price, 0) AS price,
			COALESCE(er.qty, 0) * COALESCE(er.price, 0) AS total_cost,
			COALESCE(e.realization_date, DATE(er.created_at)) AS realization_date
		`).
		Joins("JOIN expense_nonstocks AS en ON en.id = er.expense_nonstock_id").
		Joins("JOIN expenses AS e ON e.id = en.expense_id").
		Joins("LEFT JOIN nonstocks AS n ON n.id = en.nonstock_id").
		Joins("LEFT JOIN flags AS f ON f.flagable_id = n.id AND f.flagable_type = ? AND f.name = ?", entity.FlagableTypeNonstock, utils.FlagEkspedisi).
		Where("e.deleted_at IS NULL").
		Where("e.category = ?", utils.ExpenseCategoryBOP).
		Where("en.project_flock_kandang_id IN ?", projectFlockKandangIDs).
		Where("COALESCE(e.realization_date, DATE(er.created_at)) <= ?", *date)

	if ekspedisi {
		query = query.Where("f.id IS NOT NULL")
	} else {
		query = query.Where("f.id IS NULL")
	}

	if err := query.
		Order("COALESCE(e.realization_date, DATE(er.created_at)) ASC, er.id ASC").
		Scan(&rows).Error; err != nil {
		return nil, err
	}

	return rows, nil
}

func (r *HppV2RepositoryImpl) ListExpenseRealizationRowsByProjectFlockID(
	ctx context.Context,
	projectFlockID uint,
	date *time.Time,
	ekspedisi bool,
) ([]HppV2ExpenseCostRow, error) {
	if projectFlockID == 0 {
		return []HppV2ExpenseCostRow{}, nil
	}
	if date == nil {
		now := time.Now()
		date = &now
	}

	rows := make([]HppV2ExpenseCostRow, 0)
	query := r.db.WithContext(ctx).
		Table("expense_realizations AS er").
		Select(`
			er.id AS expense_realization_id,
			en.id AS expense_nonstock_id,
			e.id AS expense_id,
			COALESCE(n.id, 0) AS nonstock_id,
			COALESCE(n.name, '') AS nonstock_name,
			COALESCE(er.qty, 0) AS qty,
			COALESCE(er.price, 0) AS price,
			COALESCE(er.qty, 0) * COALESCE(er.price, 0) AS total_cost,
			COALESCE(e.realization_date, DATE(er.created_at)) AS realization_date
		`).
		Joins("JOIN expense_nonstocks AS en ON en.id = er.expense_nonstock_id").
		Joins("JOIN expenses AS e ON e.id = en.expense_id").
		Joins("LEFT JOIN nonstocks AS n ON n.id = en.nonstock_id").
		Joins("LEFT JOIN flags AS f ON f.flagable_id = n.id AND f.flagable_type = ? AND f.name = ?", entity.FlagableTypeNonstock, utils.FlagEkspedisi).
		Where("e.deleted_at IS NULL").
		Where("e.category = ?", utils.ExpenseCategoryBOP).
		Where("en.project_flock_kandang_id IS NULL").
		Where("e.project_flock_id IS NOT NULL").
		Where("e.project_flock_id::jsonb @> ?::jsonb", fmt.Sprintf("[%d]", projectFlockID)).
		Where("COALESCE(e.realization_date, DATE(er.created_at)) <= ?", *date)

	if ekspedisi {
		query = query.Where("f.id IS NOT NULL")
	} else {
		query = query.Where("f.id IS NULL")
	}

	if err := query.
		Order("COALESCE(e.realization_date, DATE(er.created_at)) ASC, er.id ASC").
		Scan(&rows).Error; err != nil {
		return nil, err
	}

	return rows, nil
}

func (r *HppV2RepositoryImpl) GetFeedUsageCost(ctx context.Context, projectFlockKandangIDs []uint, date *time.Time) (float64, error) {
	if date == nil {
		now := time.Now()
		date = &now
	}

	stockablePurchase := fifo.StockableKeyPurchaseItems.String()
	stockableAdjustment := fifo.StockableKeyAdjustmentIn.String()
	usableRecordingStock := fifo.UsableKeyRecordingStock.String()

	var total float64
	err := r.db.WithContext(ctx).
		Table("recordings AS r").
		Select(`
			COALESCE(SUM(sa.qty * CASE
				WHEN sa.stockable_type = ? THEN COALESCE(pi.price, 0)
				WHEN sa.stockable_type = ? THEN COALESCE(ast.price, 0)
				ELSE 0
			END), 0)`,
			stockablePurchase,
			stockableAdjustment,
		).
		Joins("JOIN recording_stocks AS rs ON rs.recording_id = r.id").
		Joins("JOIN product_warehouses AS pw ON pw.id = rs.product_warehouse_id").
		Joins("JOIN flags AS f ON f.flagable_id = pw.product_id AND f.flagable_type = ?", entity.FlagableTypeProduct).
		Joins(
			"JOIN stock_allocations AS sa ON sa.usable_type = ? AND sa.usable_id = rs.id AND (sa.stockable_type = ? OR sa.stockable_type = ?) AND sa.status = ? AND sa.allocation_purpose = ?",
			usableRecordingStock,
			stockablePurchase,
			stockableAdjustment,
			entity.StockAllocationStatusActive,
			entity.StockAllocationPurposeConsume,
		).
		Joins("LEFT JOIN purchase_items AS pi ON pi.id = sa.stockable_id AND sa.stockable_type = ?", stockablePurchase).
		Joins("LEFT JOIN adjustment_stocks AS ast ON ast.id = sa.stockable_id AND sa.stockable_type = ?", stockableAdjustment).
		Where("rs.project_flock_kandang_id IN (?)", projectFlockKandangIDs).
		Where("r.record_datetime <= ?", *date).
		Where("f.name = ?", utils.FlagPakan).
		Scan(&total).Error
	if err != nil {
		return 0, err
	}

	return total, nil
}

func (r *HppV2RepositoryImpl) GetTotalPopulation(ctx context.Context, projectFlockKandangIDs []uint) (float64, error) {
	var total float64
	err := r.db.WithContext(ctx).
		Table("project_chickins AS pc").
		Select("COALESCE(SUM(pc.usage_qty), 0)").
		Where("pc.project_flock_kandang_id IN (?)", projectFlockKandangIDs).
		Scan(&total).Error
	if err != nil {
		return 0, err
	}

	return total, nil
}

func (r *HppV2RepositoryImpl) GetEggProduksiPiecesAndWeightKgByProjectFlockKandangIds(ctx context.Context, projectFlockKandangIDs []uint, date *time.Time) (float64, float64, error) {
	rQty, rWeight, aQty, aWeight, err := r.GetEggProduksiBreakdownByProjectFlockKandangIds(ctx, projectFlockKandangIDs, date)
	if err != nil {
		return 0, 0, err
	}
	return rQty + aQty, rWeight + aWeight, nil
}

func (r *HppV2RepositoryImpl) GetEggProduksiBreakdownByProjectFlockKandangIds(ctx context.Context, projectFlockKandangIDs []uint, date *time.Time) (recordingQty, recordingWeight, adjustmentQty, adjustmentWeight float64, err error) {
	if date == nil {
		now := time.Now()
		date = &now
	}

	var recordingTotals struct {
		TotalPieces   float64
		TotalWeightKg float64
	}
	err = r.db.WithContext(ctx).
		Table("recordings AS r").
		Select("COALESCE(SUM(re.qty), 0) AS total_pieces, COALESCE(SUM(re.weight), 0) AS total_weight_kg").
		Joins("JOIN recording_eggs AS re ON re.recording_id = r.id").
		Where("r.project_flock_kandangs_id IN (?)", projectFlockKandangIDs).
		Where("r.record_datetime <= ?", *date).
		Scan(&recordingTotals).Error
	if err != nil {
		return 0, 0, 0, 0, err
	}

	var adjustmentTotals struct {
		TotalQty    float64
		TotalWeight float64
	}
	err = r.db.WithContext(ctx).
		Table("adjustment_stocks AS ast").
		Select("COALESCE(SUM(ast.total_qty), 0) AS total_qty, COALESCE(SUM(ast.price), 0) AS total_weight").
		Joins("JOIN product_warehouses AS pw ON pw.id = ast.product_warehouse_id").
		Where("pw.project_flock_kandang_id IN (?)", projectFlockKandangIDs).
		Where("ast.function_code = ?", string(utils.AdjustmentTransactionSubtypeRecordingEggIn)).
		Scan(&adjustmentTotals).Error
	if err != nil {
		return 0, 0, 0, 0, err
	}

	return recordingTotals.TotalPieces, recordingTotals.TotalWeightKg, adjustmentTotals.TotalQty, adjustmentTotals.TotalWeight, nil
}

func (r *HppV2RepositoryImpl) GetEggTerjualPiecesAndWeightKgByProjectFlockKandangIds(
	ctx context.Context,
	projectFlockKandangIDs []uint,
	startDate *time.Time,
	endDate *time.Time,
) (float64, float64, error) {
	if len(projectFlockKandangIDs) == 0 {
		return 0, 0, nil
	}
	if endDate == nil {
		now := time.Now()
		endDate = &now
	}
	if startDate == nil {
		startDate = endDate
	}

	eggFlags := []string{
		string(utils.FlagTelur),
		string(utils.FlagTelurUtuh),
		string(utils.FlagTelurPecah),
		string(utils.FlagTelurPutih),
		string(utils.FlagTelurRetak),
		string(utils.FlagTelurPapacal),
		string(utils.FlagTelurJumbo),
	}

	query := `
WITH selected_pfk AS (
	SELECT pfk.id, k.location_id
	FROM project_flock_kandangs pfk
	JOIN kandangs k ON k.id = pfk.kandang_id
	WHERE pfk.id IN ?
),
selected_locations AS (
	SELECT DISTINCT location_id
	FROM selected_pfk
),
sales_kandang AS (
	SELECT DISTINCT
		mdp.id AS mdp_id,
		COALESCE(mdp.usage_qty, 0) AS usage_qty,
		COALESCE(mdp.total_weight, 0) AS total_weight
	FROM marketing_delivery_products mdp
	JOIN marketing_products mp ON mp.id = mdp.marketing_product_id
	JOIN product_warehouses pw ON pw.id = mp.product_warehouse_id
	JOIN warehouses w ON w.id = pw.warehouse_id
	WHERE mdp.delivery_date IS NOT NULL
			AND mdp.delivery_date <= ?
		AND UPPER(COALESCE(w.type, '')) = 'KANDANG'
		AND pw.project_flock_kandang_id IN (SELECT id FROM selected_pfk)
		AND EXISTS (
			SELECT 1
			FROM recording_eggs re
			JOIN recordings rr ON rr.id = re.recording_id
			WHERE re.product_warehouse_id = mp.product_warehouse_id
				AND COALESCE(re.project_flock_kandang_id, rr.project_flock_kandangs_id) IN (SELECT id FROM selected_pfk)
				AND rr.deleted_at IS NULL
				AND DATE(rr.record_datetime) <= DATE(mdp.delivery_date)
		)
		AND EXISTS (
			SELECT 1
			FROM flags f
			WHERE f.flagable_type = ?
				AND f.flagable_id = pw.product_id
				AND f.name IN ?
		)
),
sales_lokasi AS (
	SELECT DISTINCT
		mdp.id AS mdp_id,
		COALESCE(mdp.usage_qty, 0) AS usage_qty,
		COALESCE(mdp.total_weight, 0) AS total_weight,
		mdp.delivery_date AS delivery_date,
		pw.id AS lokasi_pw_id,
		pw.product_id AS product_id,
		w.location_id AS location_id
	FROM marketing_delivery_products mdp
	JOIN marketing_products mp ON mp.id = mdp.marketing_product_id
	JOIN product_warehouses pw ON pw.id = mp.product_warehouse_id
	JOIN warehouses w ON w.id = pw.warehouse_id
	WHERE mdp.delivery_date IS NOT NULL
			AND mdp.delivery_date <= ?
		AND UPPER(COALESCE(w.type, '')) = 'LOKASI'
		AND w.location_id IN (SELECT location_id FROM selected_locations)
		AND EXISTS (
			SELECT 1
			FROM flags f
			WHERE f.flagable_type = ?
				AND f.flagable_id = pw.product_id
				AND f.name IN ?
		)
),
transfer_pairs AS (
	SELECT
		std.source_product_warehouse_id AS source_pw_id,
		std.dest_product_warehouse_id AS dest_pw_id,
		MIN(st.transfer_date) AS first_transfer_date
	FROM stock_transfer_details std
	JOIN stock_transfers st ON st.id = std.stock_transfer_id
	WHERE std.source_product_warehouse_id IS NOT NULL
		AND std.dest_product_warehouse_id IS NOT NULL
	GROUP BY std.source_product_warehouse_id, std.dest_product_warehouse_id
),
adj_pool AS (
	SELECT
		sl.mdp_id,
		SUM(CASE
			WHEN spw.project_flock_kandang_id IN (SELECT id FROM selected_pfk)
				THEN COALESCE(ast.usage_qty, 0)
			ELSE 0
		END) AS sel_usage_qty,
		SUM(COALESCE(ast.usage_qty, 0)) AS farm_usage_qty,
		SUM(CASE
			WHEN spw.project_flock_kandang_id IN (SELECT id FROM selected_pfk)
				THEN COALESCE(ast.price, 0)
			ELSE 0
		END) AS sel_price_sum,
		SUM(COALESCE(ast.price, 0)) AS farm_price_sum
	FROM sales_lokasi sl
	JOIN transfer_pairs tf
		ON tf.dest_pw_id = sl.lokasi_pw_id
		AND DATE(tf.first_transfer_date) <= DATE(sl.delivery_date)
	JOIN product_warehouses spw
		ON spw.id = tf.source_pw_id
		AND spw.product_id = sl.product_id
	JOIN warehouses sw ON sw.id = spw.warehouse_id
	JOIN adjustment_stocks ast ON ast.product_warehouse_id = tf.source_pw_id
	WHERE UPPER(COALESCE(sw.type, '')) = 'KANDANG'
		AND sw.location_id = sl.location_id
		AND UPPER(COALESCE(ast.function_code, '')) = UPPER(?)
		AND UPPER(COALESCE(ast.transaction_type, '')) = UPPER(?)
		AND DATE(ast.created_at) <= DATE(sl.delivery_date)
	GROUP BY sl.mdp_id
),
sales_lokasi_adj AS (
	SELECT sl.*
	FROM sales_lokasi sl
	JOIN adj_pool ap ON ap.mdp_id = sl.mdp_id
	WHERE COALESCE(ap.farm_usage_qty, 0) > 0
		OR COALESCE(ap.farm_price_sum, 0) > 0
),
sales_lokasi_rec AS (
	SELECT sl.*
	FROM sales_lokasi sl
	WHERE NOT EXISTS (
		SELECT 1 FROM sales_lokasi_adj sla WHERE sla.mdp_id = sl.mdp_id
	)
),
rec_pool AS (
	SELECT
		sl.mdp_id,
		SUM(CASE
			WHEN COALESCE(re.project_flock_kandang_id, r.project_flock_kandangs_id) IN (SELECT id FROM selected_pfk)
				THEN COALESCE(re.qty, 0)
			ELSE 0
		END) AS sel_qty,
		SUM(COALESCE(re.qty, 0)) AS farm_qty,
		SUM(CASE
			WHEN COALESCE(re.project_flock_kandang_id, r.project_flock_kandangs_id) IN (SELECT id FROM selected_pfk)
				THEN COALESCE(re.weight, 0)
			ELSE 0
		END) AS sel_weight,
		SUM(COALESCE(re.weight, 0)) AS farm_weight
	FROM sales_lokasi_rec sl
	JOIN recordings r
		ON r.deleted_at IS NULL
		AND DATE(r.record_datetime) <= DATE(sl.delivery_date)
	JOIN recording_eggs re
		ON re.recording_id = r.id
		AND re.product_warehouse_id = sl.lokasi_pw_id
	JOIN project_flock_kandangs pfk
		ON pfk.id = COALESCE(re.project_flock_kandang_id, r.project_flock_kandangs_id)
	JOIN kandangs k ON k.id = pfk.kandang_id
	WHERE k.location_id = sl.location_id
	GROUP BY sl.mdp_id
),
kandang_totals AS (
	SELECT
		COALESCE(SUM(sk.usage_qty), 0) AS total_pieces,
		COALESCE(SUM(sk.total_weight), 0) AS total_weight
	FROM sales_kandang sk
),
lokasi_adj_totals AS (
	SELECT
		COALESCE(SUM(
			sla.usage_qty *
			CASE
				WHEN COALESCE(ap.farm_usage_qty, 0) > 0 THEN (COALESCE(ap.sel_usage_qty, 0) * 1.0) / NULLIF(ap.farm_usage_qty, 0)
				ELSE 0
			END
		), 0) AS total_pieces,
		COALESCE(SUM(
			sla.total_weight *
			CASE
				WHEN COALESCE(ap.farm_price_sum, 0) > 0 THEN (COALESCE(ap.sel_price_sum, 0) * 1.0) / NULLIF(ap.farm_price_sum, 0)
				ELSE 0
			END
		), 0) AS total_weight
	FROM sales_lokasi_adj sla
	JOIN adj_pool ap ON ap.mdp_id = sla.mdp_id
),
lokasi_rec_totals AS (
	SELECT
		COALESCE(SUM(
			slr.usage_qty *
			CASE
				WHEN COALESCE(rp.farm_qty, 0) > 0 THEN (COALESCE(rp.sel_qty, 0) * 1.0) / NULLIF(rp.farm_qty, 0)
				ELSE 0
			END
		), 0) AS total_pieces,
		COALESCE(SUM(
			slr.total_weight *
			CASE
				WHEN COALESCE(rp.farm_weight, 0) > 0 THEN (COALESCE(rp.sel_weight, 0) * 1.0) / NULLIF(rp.farm_weight, 0)
				ELSE 0
			END
		), 0) AS total_weight
	FROM sales_lokasi_rec slr
	LEFT JOIN rec_pool rp ON rp.mdp_id = slr.mdp_id
)
SELECT
	COALESCE(kt.total_pieces, 0) + COALESCE(lat.total_pieces, 0) + COALESCE(lrt.total_pieces, 0) AS total_pieces,
	COALESCE(kt.total_weight, 0) + COALESCE(lat.total_weight, 0) + COALESCE(lrt.total_weight, 0) AS total_weight
FROM kandang_totals kt
CROSS JOIN lokasi_adj_totals lat
CROSS JOIN lokasi_rec_totals lrt
`

	var totals struct {
		TotalPieces float64
		TotalWeight float64
	}

	err := r.db.WithContext(ctx).
		Raw(
			query,
			projectFlockKandangIDs,
			*endDate,
			entity.FlagableTypeProduct,
			eggFlags,
			*endDate,
			entity.FlagableTypeProduct,
			eggFlags,
			string(utils.AdjustmentTransactionSubtypeRecordingEggIn),
			string(utils.AdjustmentTransactionTypeRecording),
		).
		Scan(&totals).Error
	if err != nil {
		return 0, 0, err
	}

	return totals.TotalPieces, totals.TotalWeight, nil
}

func (r *HppV2RepositoryImpl) GetTransferSourceSummary(ctx context.Context, projectFlockKandangId uint) (uint, float64, error) {
	var summary struct {
		ProjectFlockID uint
		TotalQty       float64
	}
	err := r.db.WithContext(ctx).
		Table("laying_transfer_targets AS ltt").
		Select("lt.from_project_flock_id AS project_flock_id, COALESCE(SUM(ltt.total_qty), 0) AS total_qty").
		Joins("JOIN laying_transfers AS lt ON lt.id = ltt.laying_transfer_id").
		Where("lt.deleted_at IS NULL").
		Where("ltt.deleted_at IS NULL").
		Where("lt.executed_at IS NOT NULL").
		Where("ltt.target_project_flock_kandang_id = ?", projectFlockKandangId).
		Group("lt.from_project_flock_id").
		Scan(&summary).Error
	if err != nil {
		return 0, 0, err
	}

	return summary.ProjectFlockID, summary.TotalQty, nil
}
