package dto

import (
	"time"

	entity "gitlab.com/mbugroup/lti-api.git/internal/entities"
	deliveryOrdersDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/marketing/dto"
	customerDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/customers/dto"
	kandangDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/kandangs/dto"
	productDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/products/dto"
	"gitlab.com/mbugroup/lti-api.git/internal/utils"
)

// === Response DTO ===
type SalesDTO struct {
	Id               uint                             `json:"id"`
	RealizationDate  time.Time                        `json:"realization_date"`
	Age              int                              `json:"age"`
	Week             int                              `json:"week"`
	DoNumber         string                           `json:"do_number"`
	Product          *productDTO.ProductRelationDTO   `json:"product,omitempty"`
	Customer         *customerDTO.CustomerRelationDTO `json:"customer,omitempty"`
	Qty              float64                          `json:"qty"`
	Weight           float64                          `json:"weight"`
	AvgWeight        float64                          `json:"avg_weight"`
	SalesPrice       float64                          `json:"sales_price"`
	TotalSalesPrice  float64                          `json:"total_sales_price"`
	ActualPrice      float64                          `json:"actual_price"`
	TotalActualPrice float64                          `json:"total_actual_price"`
	Kandang          *kandangDTO.KandangRelationDTO   `json:"kandang,omitempty"`
}
type SummaryDTO struct {
	TotalSalesPrice  float64 `json:"total_sales_price"`
	AvgSalesPrice    float64 `json:"avg_sales_price"`
	TotalActualPrice float64 `json:"total_actual_price"`
	AvgActualPrice   float64 `json:"avg_actual_price"`
}

type PenjualanRealisasiResponseDTO struct {
	Sales   []SalesDTO `json:"sales"`
	Summary SummaryDTO `json:"summary"`
}

// === Mapper Functions ===

func ToSalesDTO(e entity.MarketingDeliveryProduct) SalesDTO {
	projectFlockKandang := resolveMarketingDeliveryProjectFlockKandang(e)

	productFlags := make([]string, len(e.MarketingProduct.ProductWarehouse.Product.Flags))
	for i, f := range e.MarketingProduct.ProductWarehouse.Product.Flags {
		productFlags[i] = f.Name
	}

	var category string
	if projectFlockKandang != nil {
		category = projectFlockKandang.ProjectFlock.Category
	}

	ageInDay, ageInWeeks := calculateAgeFromChickin(projectFlockKandang, e.DeliveryDate, productFlags, category)

	var product *productDTO.ProductRelationDTO
	if e.MarketingProduct.ProductWarehouse.Product.Id != 0 {
		mapped := productDTO.ToProductRelationDTO(e.MarketingProduct.ProductWarehouse.Product)
		product = &mapped
	}

	var customer *customerDTO.CustomerRelationDTO
	if e.MarketingProduct.Marketing.Customer.Id != 0 {
		mapped := customerDTO.ToCustomerRelationDTO(e.MarketingProduct.Marketing.Customer)
		customer = &mapped
	}

	var kandang *kandangDTO.KandangRelationDTO
	if projectFlockKandang != nil && projectFlockKandang.Kandang.Id != 0 {
		mapped := kandangDTO.ToKandangRelationDTO(projectFlockKandang.Kandang)
		kandang = &mapped
	}

	var realizationDate time.Time
	if e.DeliveryDate != nil {
		realizationDate = *e.DeliveryDate
	}

	doNumber := deliveryOrdersDTO.GenerateDeliveryOrderNumber(e.MarketingProduct.Marketing.SoNumber, e.DeliveryDate, e.MarketingProduct.ProductWarehouse.Warehouse.Id)

	return SalesDTO{
		Id:               e.Id,
		RealizationDate:  realizationDate,
		Age:              ageInDay,
		Week:             ageInWeeks,
		DoNumber:         doNumber,
		Product:          product,
		Customer:         customer,
		Qty:              e.UsageQty,
		Weight:           e.TotalWeight,
		AvgWeight:        e.AvgWeight,
		SalesPrice:       e.MarketingProduct.UnitPrice,
		TotalSalesPrice:  e.MarketingProduct.TotalPrice,
		ActualPrice:      e.UnitPrice,
		TotalActualPrice: e.TotalPrice,
		Kandang:          kandang,
	}
}

func ToSalesAgeDTO(e entity.MarketingDeliveryProduct) SalesDTO {
	projectFlockKandang := resolveMarketingDeliveryProjectFlockKandang(e)

	productFlags := make([]string, len(e.MarketingProduct.ProductWarehouse.Product.Flags))
	for i, f := range e.MarketingProduct.ProductWarehouse.Product.Flags {
		productFlags[i] = f.Name
	}

	var category string
	if projectFlockKandang != nil {
		category = projectFlockKandang.ProjectFlock.Category
	}

	ageInDay, _ := calculateAgeFromChickin(projectFlockKandang, e.DeliveryDate, productFlags, category)

	return SalesDTO{
		Age: ageInDay,
		Qty: e.UsageQty,
	}
}

func ToSummaryDto(e []entity.MarketingDeliveryProduct) SummaryDTO {
	var totalSalesPrice, totalActualPrice, sumSales, sumActual float64
	count := len(e)

	if count == 0 {
		return SummaryDTO{
			TotalSalesPrice:  0,
			TotalActualPrice: 0,
			AvgSalesPrice:    0,
			AvgActualPrice:   0,
		}
	}

	for _, item := range e {
		totalSalesPrice += item.MarketingProduct.TotalPrice
		totalActualPrice += item.TotalPrice
		sumSales += item.MarketingProduct.UnitPrice
		sumActual += item.UnitPrice
	}

	return SummaryDTO{
		TotalSalesPrice:  totalSalesPrice,
		TotalActualPrice: totalActualPrice,
		AvgSalesPrice:    sumSales / float64(count),
		AvgActualPrice:   sumActual / float64(count),
	}
}

func ToSalesDTOs(e []entity.MarketingDeliveryProduct) []SalesDTO {
	result := make([]SalesDTO, len(e))
	for i, r := range e {
		result[i] = ToSalesDTO(r)
	}
	return result
}

func ToPenjualanRealisasiResponseDTO(e []entity.MarketingDeliveryProduct) PenjualanRealisasiResponseDTO {
	return PenjualanRealisasiResponseDTO{
		Sales:   ToSalesDTOs(e),
		Summary: ToSummaryDto(e),
	}
}

func resolveMarketingDeliveryProjectFlockKandang(e entity.MarketingDeliveryProduct) *entity.ProjectFlockKandang {
	if e.AttributedProjectFlockKandang != nil {
		return e.AttributedProjectFlockKandang
	}
	return e.MarketingProduct.ProductWarehouse.ProjectFlockKandang
}

func calculateAgeFromChickin(projectFlockKandang *entity.ProjectFlockKandang, deliveryDate *time.Time, productFlags []string, category string) (int, int) {
	if projectFlockKandang == nil || deliveryDate == nil || len(projectFlockKandang.Chickins) == 0 {
		return 0, 0
	}

	for _, flag := range productFlags {
		if flag == string(utils.FlagOVK) ||
			flag == string(utils.FlagPakan) ||
			flag == string(utils.FlagPreStarter) ||
			flag == string(utils.FlagStarter) ||
			flag == string(utils.FlagFinisher) ||
			flag == string(utils.FlagObat) ||
			flag == string(utils.FlagVitamin) ||
			flag == string(utils.FlagKimia) ||
			flag == string(utils.FlagEkspedisi) ||
			flag == string(utils.FlagTelur) ||
			flag == string(utils.FlagTelurUtuh) ||
			flag == string(utils.FlagTelurPecah) ||
			flag == string(utils.FlagTelurPutih) ||
			flag == string(utils.FlagTelurRetak) {
			return 0, 0
		}
	}

	earliestChickinDate := projectFlockKandang.Chickins[0].ChickInDate
	for _, chickin := range projectFlockKandang.Chickins {
		if chickin.ChickInDate.Before(earliestChickinDate) {
			earliestChickinDate = chickin.ChickInDate
		}
	}

	diff := deliveryDate.Sub(earliestChickinDate)
	ageInDays := int(diff.Hours() / 24)

	var ageInWeeks int
	if ageInDays <= 0 {
		ageInWeeks = 0
	} else {
		if category == string(utils.ProjectFlockCategoryLaying) {
			ageInDays = ageInDays + 119
			ageInWeeks = ((ageInDays - 1) / 7) + 1
		} else {
			ageInWeeks = ((ageInDays - 1) / 7) + 1
		}
	}

	return ageInDays, ageInWeeks
}
