package service

import (
	"errors"

	"github.com/gofiber/fiber/v2"
	"github.com/sirupsen/logrus"
	commonRepo "gitlab.com/mbugroup/lti-api.git/internal/common/repository"
	commonSvc "gitlab.com/mbugroup/lti-api.git/internal/common/service"
	entity "gitlab.com/mbugroup/lti-api.git/internal/entities"
	"gitlab.com/mbugroup/lti-api.git/internal/modules/closings/dto"
	expenseRealizationRepository "gitlab.com/mbugroup/lti-api.git/internal/modules/expenses/repositories"
	marketingDeliveryProductRepository "gitlab.com/mbugroup/lti-api.git/internal/modules/marketing/repositories"
	chickinRepository "gitlab.com/mbugroup/lti-api.git/internal/modules/production/chickins/repositories"
	projectflockRepository "gitlab.com/mbugroup/lti-api.git/internal/modules/production/project_flocks/repositories"
	recordingRepository "gitlab.com/mbugroup/lti-api.git/internal/modules/production/recordings/repositories"
	"gitlab.com/mbugroup/lti-api.git/internal/utils"
	"gorm.io/gorm"
)

// ClosingKeuanganService handles closing keuangan business logic
type ClosingKeuanganService interface {
	GetClosingKeuangan(ctx *fiber.Ctx, projectFlockID uint) (*dto.ClosingKeuanganData, error)
	GetClosingKeuanganByKandang(ctx *fiber.Ctx, projectFlockID uint, projectFlockKandangID uint) (*dto.ClosingKeuanganData, error)
}

// CostData holds all cost-related information
type CostData struct {
	FeedCost               float64
	OvkCost                float64
	ChickenCost            float64
	ExpeditionCost         float64
	BudgetOperational      float64
	RealizationOperational float64
}

// ProductionData holds all production and sales related information
type ProductionData struct {
	TotalPopulationIn   float64
	TotalDepletion      float64
	TotalWeightProduced float64
	TotalEggWeightKg    float64
	TotalWeightSold     float64
	TotalBirdSold       float64
	TotalSalesAmount    float64
}

type closingKeuanganService struct {
	Log                          *logrus.Logger
	ProjectFlockRepo             projectflockRepository.ProjectflockRepository
	ProjectFlockKandangRepo      projectflockRepository.ProjectFlockKandangRepository
	MarketingDeliveryProductRepo marketingDeliveryProductRepository.MarketingDeliveryProductRepository
	ExpenseRealizationRepo       expenseRealizationRepository.ExpenseRealizationRepository
	ProjectBudgetRepo            projectflockRepository.ProjectBudgetRepository
	ChickinRepo                  chickinRepository.ProjectChickinRepository
	RecordingRepo                recordingRepository.RecordingRepository
	HppSvc                       commonSvc.HppService
	HppRepo                      commonRepo.HppCostRepository
}

func NewClosingKeuanganService(
	projectFlockRepo projectflockRepository.ProjectflockRepository,
	projectFlockKandangRepo projectflockRepository.ProjectFlockKandangRepository,
	marketingDeliveryProductRepo marketingDeliveryProductRepository.MarketingDeliveryProductRepository,
	expenseRealizationRepo expenseRealizationRepository.ExpenseRealizationRepository,
	projectBudgetRepo projectflockRepository.ProjectBudgetRepository,
	chickinRepo chickinRepository.ProjectChickinRepository,
	recordingRepo recordingRepository.RecordingRepository,
	hppSvc commonSvc.HppService,
	hppRepo commonRepo.HppCostRepository,
) ClosingKeuanganService {
	return &closingKeuanganService{
		Log:                          utils.Log,
		ProjectFlockRepo:             projectFlockRepo,
		ProjectFlockKandangRepo:      projectFlockKandangRepo,
		MarketingDeliveryProductRepo: marketingDeliveryProductRepo,
		ExpenseRealizationRepo:       expenseRealizationRepo,
		ProjectBudgetRepo:            projectBudgetRepo,
		ChickinRepo:                  chickinRepo,
		RecordingRepo:                recordingRepo,
		HppSvc:                       hppSvc,
		HppRepo:                      hppRepo,
	}
}

func (s closingKeuanganService) GetClosingKeuangan(c *fiber.Ctx, projectFlockID uint) (*dto.ClosingKeuanganData, error) {

	if err := commonSvc.EnsureRelations(c.Context(),
		commonSvc.RelationCheck{Name: "Project Flock", ID: &projectFlockID, Exists: s.ProjectFlockRepo.IdExists},
	); err != nil {
		return nil, err
	}

	projectFlock, err := s.ProjectFlockRepo.GetByID(c.Context(), projectFlockID, nil)
	if err != nil {
		return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch project flock")
	}

	projectFlockKandangs, err := s.ProjectFlockKandangRepo.GetByProjectFlockID(c.Context(), projectFlockID)
	if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
		return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch kandangs")
	}

	return s.calculateClosingKeuangan(c, projectFlock, projectFlockKandangs)
}

func (s closingKeuanganService) GetClosingKeuanganByKandang(c *fiber.Ctx, projectFlockID uint, projectFlockKandangID uint) (*dto.ClosingKeuanganData, error) {

	if err := commonSvc.EnsureRelations(c.Context(),
		commonSvc.RelationCheck{Name: "Project Flock", ID: &projectFlockID, Exists: s.ProjectFlockRepo.IdExists},
	); err != nil {
		return nil, err
	}

	projectFlockKandang, err := s.ProjectFlockKandangRepo.GetByID(c.Context(), projectFlockKandangID)
	if err != nil {
		return nil, fiber.NewError(fiber.StatusNotFound, "Project flock kandang not found")
	}
	if projectFlockKandang.ProjectFlockId != projectFlockID {
		return nil, fiber.NewError(fiber.StatusBadRequest, "Project flock kandang does not belong to this project flock")
	}

	projectFlock, err := s.ProjectFlockRepo.GetByID(c.Context(), projectFlockID, nil)
	if err != nil {
		return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch project flock")
	}

	projectFlockKandangs := []entity.ProjectFlockKandang{*projectFlockKandang}

	return s.calculateClosingKeuangan(c, projectFlock, projectFlockKandangs)
}

func (s closingKeuanganService) calculateClosingKeuangan(c *fiber.Ctx, projectFlock *entity.ProjectFlock, projectFlockKandangs []entity.ProjectFlockKandang) (*dto.ClosingKeuanganData, error) {

	var projectFlockKandangIDs []uint
	for _, projectFlockKandang := range projectFlockKandangs {
		projectFlockKandangIDs = append(projectFlockKandangIDs, projectFlockKandang.Id)
	}

	isPerKandang := len(projectFlockKandangs) == 1
	var projectFlockKandangID *uint
	if isPerKandang {
		kandangID := projectFlockKandangs[0].Id
		projectFlockKandangID = &kandangID
	}

	costs, err := s.calculateCosts(c, projectFlock, projectFlockKandangs, projectFlockKandangIDs, projectFlockKandangID)
	if err != nil {
		return nil, err
	}

	productionData, err := s.calculateProductionData(c, projectFlock, projectFlockKandangIDs, projectFlockKandangID)
	if err != nil {
		return nil, err
	}

	hppSection := s.buildHPPSection(c, projectFlock, projectFlockKandangs, costs, productionData)

	profitLossSection := s.buildProfitLossSection(projectFlock, costs, productionData)

	data := dto.ToClosingKeuanganData(hppSection, profitLossSection)
	return &data, nil
}

func (s closingKeuanganService) calculateCosts(c *fiber.Ctx, projectFlock *entity.ProjectFlock, projectFlockKandangs []entity.ProjectFlockKandang, projectFlockKandangIDs []uint, projectFlockKandangID *uint) (*CostData, error) {
	costs := &CostData{}
	var err error

	costs.FeedCost, err = s.HppRepo.GetFeedUsageCost(c.Context(), projectFlockKandangIDs, nil)
	if err != nil {
		costs.FeedCost = 0
	}

	costs.OvkCost, err = s.HppRepo.GetOvkUsageCost(c.Context(), projectFlockKandangIDs, nil)
	if err != nil {
		costs.OvkCost = 0
	}

	if projectFlock.Category == string(utils.ProjectFlockCategoryLaying) {
		for _, projectFlockKandang := range projectFlockKandangs {
			depresiasiCost, err := s.HppSvc.GetDepresiasiTransfer(projectFlockKandang.Id, nil)
			if err == nil {
				costs.ChickenCost += depresiasiCost
			}
			pulletCost, err := s.HppRepo.GetPulletCost(c.Context(), projectFlockKandang.Id)
			if err == nil {
				costs.ChickenCost += pulletCost
			}
		}
	} else {
		for _, projectFlockKandang := range projectFlockKandangs {
			pulletCost, err := s.HppRepo.GetPulletCost(c.Context(), projectFlockKandang.Id)
			if err == nil {
				costs.ChickenCost += pulletCost
			}
		}
	}

	costs.ExpeditionCost, err = s.HppRepo.GetExpedisionCost(c.Context(), projectFlockKandangIDs)
	if err != nil {
		costs.ExpeditionCost = 0
	}

	if budgets, err := s.ProjectBudgetRepo.GetByProjectFlockID(c.Context(), projectFlock.Id); err == nil {
		totalBudget := 0.0
		for _, budget := range budgets {
			totalBudget += budget.Price * budget.Qty
		}
		if projectFlockKandangID != nil {
			allKandangs, errKandang := s.ProjectFlockKandangRepo.GetByProjectFlockID(c.Context(), projectFlock.Id)
			if errKandang == nil && len(allKandangs) > 0 {
				costs.BudgetOperational = totalBudget / float64(len(allKandangs))
			}
		} else {
			costs.BudgetOperational = totalBudget
		}
	} else if !errors.Is(err, gorm.ErrRecordNotFound) {
		s.Log.Errorf("Failed to fetch budgets for project_flock_id=%d: %+v", projectFlock.Id, err)
	}

	if realizations, err := s.ExpenseRealizationRepo.GetClosingOverhead(c.Context(), projectFlock.Id, projectFlockKandangID); err == nil {
		for _, realization := range realizations {
			amount := realization.Price * realization.Qty
			isEkspedisi := realization.ExpenseNonstock != nil &&
				realization.ExpenseNonstock.Nonstock != nil &&
				containsFlag(realization.ExpenseNonstock.Nonstock.Flags, "EKSPEDISI")
			if !isEkspedisi {
				costs.RealizationOperational += amount
			}
		}
	} else if !errors.Is(err, gorm.ErrRecordNotFound) {
		s.Log.Errorf("Failed to fetch realizations for project_flock_id=%d: %+v", projectFlock.Id, err)
	}

	return costs, nil
}

func (s closingKeuanganService) calculateProductionData(c *fiber.Ctx, projectFlock *entity.ProjectFlock, projectFlockKandangIDs []uint, projectFlockKandangID *uint) (*ProductionData, error) {
	data := &ProductionData{}
	var err error

	data.TotalPopulationIn, err = s.HppRepo.GetTotalPopulation(c.Context(), projectFlockKandangIDs)
	if err != nil {
		data.TotalPopulationIn = 0
	}

	if projectFlockKandangID != nil {
		data.TotalDepletion, err = s.RecordingRepo.GetTotalDepletionByProjectFlockKandangID(c.Context(), *projectFlockKandangID)
	} else {
		data.TotalDepletion, err = s.RecordingRepo.GetTotalDepletionByProjectFlockID(c.Context(), projectFlock.Id)
	}
	if err != nil {
		data.TotalDepletion = 0
	}

	if projectFlockKandangID != nil {
		data.TotalWeightProduced, err = s.RecordingRepo.GetTotalWeightProducedFromUniformityByProjectFlockKandangID(c.Context(), *projectFlockKandangID)
	} else {
		data.TotalWeightProduced, err = s.RecordingRepo.GetTotalWeightProducedFromUniformityByProjectFlockID(c.Context(), projectFlock.Id)
	}
	if err != nil {
		data.TotalWeightProduced = 0
	}

	if projectFlock.Category == string(utils.ProjectFlockCategoryLaying) {
		_, data.TotalEggWeightKg, err = s.HppRepo.GetEggProduksiPiecesAndWeightKgByProjectFlockKandangIds(c.Context(), projectFlockKandangIDs, nil)
		if err != nil {
			data.TotalEggWeightKg = 0
		}
	}

	var deliveryProducts []entity.MarketingDeliveryProduct
	if projectFlockKandangID != nil {
		deliveryProducts, err = s.MarketingDeliveryProductRepo.GetClosingPenjualanByCategory(c.Context(), projectFlock.Id, projectFlockKandangID, projectFlock.Category)
	} else {
		deliveryProducts, err = s.MarketingDeliveryProductRepo.GetClosingPenjualanByCategory(c.Context(), projectFlock.Id, nil, projectFlock.Category)
	}
	if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
		return nil, fiber.NewError(fiber.StatusInternalServerError, "Gagal mengambil data penjualan")
	}

	for _, delivery := range deliveryProducts {
		if delivery.MarketingProduct.ProductWarehouse.Product.Id == 0 {
			continue
		}
		data.TotalWeightSold += delivery.TotalWeight
		data.TotalBirdSold += delivery.UsageQty
		data.TotalSalesAmount += delivery.TotalPrice
	}

	return data, nil
}

func (s closingKeuanganService) buildHPPSection(c *fiber.Ctx, projectFlock *entity.ProjectFlock, projectFlockKandangs []entity.ProjectFlockKandang, costs *CostData, production *ProductionData) dto.HPPSection {

	actualPopulation := production.TotalPopulationIn - production.TotalDepletion
	if lastPopulation, ok := s.getLastPopulationFromRecordings(c, projectFlockKandangs); ok {
		actualPopulation = lastPopulation
	}
	totalWeightProduced := production.TotalWeightProduced
	totalEggWeightKg := production.TotalEggWeightKg

	weightForCalculation := totalWeightProduced
	if projectFlock.Category == string(utils.ProjectFlockCategoryLaying) {
		weightForCalculation = totalEggWeightKg
	}

	calculateMetrics := func(amount float64) (rpPerBird, rpPerKg float64) {
		if actualPopulation > 0 {
			rpPerBird = amount / actualPopulation
		}
		if weightForCalculation > 0 {
			rpPerKg = amount / weightForCalculation
		}
		return
	}

	createHPPItem := func(id uint, category, code, label string, budgetAmount, realizationAmount float64) dto.HPPItem {
		budgetRpPerBird, budgetRpPerKg := calculateMetrics(budgetAmount)
		realizationRpPerBird, realizationRpPerKg := calculateMetrics(realizationAmount)
		return dto.ToHPPItem(
			id,
			category,
			code,
			label,
			dto.ToFinancialMetrics(budgetRpPerBird, budgetRpPerKg, budgetAmount),
			dto.ToFinancialMetrics(realizationRpPerBird, realizationRpPerKg, realizationAmount),
		)
	}

	hppItems := []dto.HPPItem{}

	hppItems = append(hppItems, createHPPItem(1, "purchase", string(dto.HPPCodePakan), "Pembelian Pakan", costs.FeedCost, costs.FeedCost))
	hppItems = append(hppItems, createHPPItem(2, "purchase", string(dto.HPPCodeOVK), "Pembelian OVK", costs.OvkCost, costs.OvkCost))

	docCode := string(dto.HPPCodeDOC)
	docLabel := "Pembelian DOC"
	if projectFlock.Category == string(utils.ProjectFlockCategoryLaying) {
		docCode = string(dto.HPPCodeDepresiasi)
		docLabel = "Depresiasi"
	}
	hppItems = append(hppItems, createHPPItem(3, "purchase", docCode, docLabel, costs.ChickenCost, costs.ChickenCost))
	hppItems = append(hppItems, createHPPItem(4, "overhead", string(dto.HPPCodeOverhead), "Pengeluaran Overhead", costs.BudgetOperational, costs.RealizationOperational))
	hppItems = append(hppItems, createHPPItem(5, "overhead", string(dto.HPPCodeEkspedisi), "Beban Ekspedisi", costs.ExpeditionCost, costs.ExpeditionCost))

	totalBudgetHpp := costs.FeedCost + costs.OvkCost + costs.ChickenCost + costs.BudgetOperational + costs.ExpeditionCost
	totalRealizationHpp := costs.FeedCost + costs.OvkCost + costs.ChickenCost + costs.RealizationOperational + costs.ExpeditionCost

	hppBudgetRpPerBird, hppBudgetRpPerKg := calculateMetrics(totalBudgetHpp)
	hppRealizationRpPerBird, hppRealizationRpPerKg := calculateMetrics(totalRealizationHpp)

	var eggBudgeting, eggRealization *dto.FinancialMetrics
	if projectFlock.Category == string(utils.ProjectFlockCategoryLaying) {
		accumulateEggMetrics := func(metrics **dto.FinancialMetrics, amount, rpPerKg float64) {
			if *metrics == nil {
				*metrics = &dto.FinancialMetrics{
					RpPerBird: 0,
					RpPerKg:   rpPerKg,
					Amount:    amount,
				}
			} else {
				(*metrics).Amount += amount
				if totalEggWeightKg > 0 {
					(*metrics).RpPerKg = (*metrics).Amount / totalEggWeightKg
				}
			}
		}

		for _, projectFlockKandang := range projectFlockKandangs {
			hppResponse, err := s.HppSvc.CalculateHppCost(projectFlockKandang.Id, nil)
			if err == nil {
				accumulateEggMetrics(&eggBudgeting, hppResponse.Estimation.Total, hppResponse.Estimation.HargaKg)
				accumulateEggMetrics(&eggRealization, hppResponse.Real.Total, hppResponse.Real.HargaKg)
			}
		}
	}

	hppSummary := dto.ToHPPSummary(
		"HPP",
		dto.ToFinancialMetrics(hppBudgetRpPerBird, hppBudgetRpPerKg, totalBudgetHpp),
		dto.ToFinancialMetrics(hppRealizationRpPerBird, hppRealizationRpPerKg, totalRealizationHpp),
		eggBudgeting,
		eggRealization,
	)

	return dto.ToHPPSection(hppItems, hppSummary)
}

func (s closingKeuanganService) buildProfitLossSection(projectFlock *entity.ProjectFlock, costs *CostData, production *ProductionData) dto.ProfitLossSection {

	totalWeightProduced := production.TotalWeightProduced
	totalEggWeightKg := production.TotalEggWeightKg
	totalSalesAmount := production.TotalSalesAmount
	totalWeightSold := production.TotalWeightSold
	totalBirdSold := production.TotalBirdSold
	actualPopulation := production.TotalPopulationIn - production.TotalDepletion

	isLaying := projectFlock.Category == string(utils.ProjectFlockCategoryLaying)

	// Fungsi untuk sales: LAYING = populasi aktual, GROWING = ekor terjual
	calculateSalesMetrics := func(amount float64) (rpPerBird, rpPerKg float64) {
		if isLaying {
			if actualPopulation > 0 {
				rpPerBird = amount / actualPopulation
			}
			if totalWeightSold > 0 {
				rpPerKg = amount / totalWeightSold
			}
		} else {
			if totalBirdSold > 0 {
				rpPerBird = amount / totalBirdSold
			}
			if totalWeightSold > 0 {
				rpPerKg = amount / totalWeightSold
			}
		}
		return
	}

	// Fungsi untuk cost: per ekor = populasi aktual, per kg = LAYING telur produksi / GROWING ayam produksi
	calculateCostMetrics := func(amount float64) (rpPerBird, rpPerKg float64) {
		if actualPopulation > 0 {
			rpPerBird = amount / actualPopulation
		}
		if isLaying {
			if totalEggWeightKg > 0 {
				rpPerKg = amount / totalEggWeightKg
			}
		} else {
			if totalWeightProduced > 0 {
				rpPerKg = amount / totalWeightProduced
			}
		}
		return
	}

	// Fungsi untuk overhead/ekspedisi: LAYING = populasi aktual, GROWING = ekor terjual
	calculateOverheadMetrics := func(amount float64) (rpPerBird, rpPerKg float64) {
		if isLaying {
			if actualPopulation > 0 {
				rpPerBird = amount / actualPopulation
			}
			if totalWeightSold > 0 {
				rpPerKg = amount / totalWeightSold
			}
		} else {
			if totalBirdSold > 0 {
				rpPerBird = amount / totalBirdSold
			}
			if totalWeightSold > 0 {
				rpPerKg = amount / totalWeightSold
			}
		}
		return
	}

	plItems := []dto.ProfitLossItem{}

	salesRpPerBird, salesRpPerKg := calculateSalesMetrics(totalSalesAmount)
	salesLabel := "Penjualan Ayam"
	if isLaying {
		salesLabel = "Penjualan Telur"
	}
	plItems = append(plItems, dto.ToProfitLossItem(
		string(dto.PLCodeSales),
		salesLabel,
		"income",
		salesRpPerBird,
		salesRpPerKg,
		totalSalesAmount,
	))

	totalSapronakAmount := costs.ChickenCost + costs.FeedCost + costs.OvkCost
	sapronakRpPerBird := 0.0
	sapronakRpPerKg := 0.0
	for _, amount := range []float64{costs.ChickenCost, costs.FeedCost, costs.OvkCost} {
		rpPerBird, rpPerKg := calculateCostMetrics(amount)
		sapronakRpPerBird += rpPerBird
		sapronakRpPerKg += rpPerKg
	}
	plItems = append(plItems, dto.ToProfitLossItem(
		string(dto.PLCodeSapronak),
		"Pengeluaran Sapronak",
		"purchase",
		sapronakRpPerBird,
		sapronakRpPerKg,
		totalSapronakAmount,
	))

	overheadRpPerBird, overheadRpPerKg := calculateOverheadMetrics(costs.RealizationOperational)
	plItems = append(plItems, dto.ToProfitLossItem(
		string(dto.PLCodeOverhead),
		"Overhead",
		"overhead",
		overheadRpPerBird,
		overheadRpPerKg,
		costs.RealizationOperational,
	))

	ekspedisiRpPerBird, ekspedisiRpPerKg := calculateOverheadMetrics(costs.ExpeditionCost)
	plItems = append(plItems, dto.ToProfitLossItem(
		string(dto.PLCodeEkspedisi),
		"Ekspedisi",
		"overhead",
		ekspedisiRpPerBird,
		ekspedisiRpPerKg,
		costs.ExpeditionCost,
	))

	costOfGoodsSold := costs.ChickenCost + costs.FeedCost + costs.OvkCost
	costOfGoodsSoldRpPerBird := sapronakRpPerBird
	costOfGoodsSoldRpPerKg := sapronakRpPerKg

	grossProfit := totalSalesAmount - costOfGoodsSold
	grossProfitRpPerBird := salesRpPerBird - costOfGoodsSoldRpPerBird
	grossProfitRpPerKg := salesRpPerKg - costOfGoodsSoldRpPerKg

	totalOperatingExpenses := costs.RealizationOperational + costs.ExpeditionCost
	totalOperatingExpensesRpPerBird := overheadRpPerBird + ekspedisiRpPerBird
	totalOperatingExpensesRpPerKg := overheadRpPerKg + ekspedisiRpPerKg

	netProfit := grossProfit - totalOperatingExpenses
	netProfitRpPerBird := grossProfitRpPerBird - totalOperatingExpensesRpPerBird
	netProfitRpPerKg := grossProfitRpPerKg - totalOperatingExpensesRpPerKg

	plSummary := dto.ToProfitLossSummary(
		dto.ToFinancialMetrics(grossProfitRpPerBird, grossProfitRpPerKg, grossProfit),
		dto.ToFinancialMetrics(totalOperatingExpensesRpPerBird, totalOperatingExpensesRpPerKg, totalOperatingExpenses),
		dto.ToFinancialMetrics(netProfitRpPerBird, netProfitRpPerKg, netProfit),
	)

	return dto.ToProfitLossSection(plItems, plSummary)
}

func (s closingKeuanganService) getLastPopulationFromRecordings(c *fiber.Ctx, projectFlockKandangs []entity.ProjectFlockKandang) (float64, bool) {
	if s.RecordingRepo == nil || len(projectFlockKandangs) == 0 {
		return 0, false
	}

	total := 0.0
	recordedCount := 0
	for _, kandang := range projectFlockKandangs {
		latest, err := s.RecordingRepo.GetLatestByProjectFlockKandangID(c.Context(), kandang.Id)
		if err != nil {
			s.Log.Errorf("Failed to fetch latest recording for project_flock_kandang_id=%d: %+v", kandang.Id, err)
			return 0, false
		}
		if latest == nil || latest.TotalChickQty == nil {
			continue
		}
		recordedCount++
		if *latest.TotalChickQty > 0 {
			total += *latest.TotalChickQty
		}
	}

	if recordedCount != len(projectFlockKandangs) {
		return 0, false
	}

	return total, true
}

func containsFlag(flags []entity.Flag, name string) bool {
	for _, flag := range flags {
		if flag.Name == name {
			return true
		}
	}
	return false
}
