package dto

import (
	"math"
	"time"

	entity "gitlab.com/mbugroup/lti-api.git/internal/entities"
	productDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/products/dto"
	supplierDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/suppliers/dto"
	warehouseDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/warehouses/dto"
)

type PurchaseSupplierRowDTO struct {
	ReceiveDate        string                             `json:"receive_date"`
	PoDate             string                             `json:"po_date"`
	PoNumber           string                             `json:"po_number"`
	Product            *productDTO.ProductRelationDTO     `json:"product,omitempty"`
	Warehouse          *warehouseDTO.WarehouseRelationDTO `json:"warehouse,omitempty"`
	Qty                float64                            `json:"qty"`
	UnitPrice          float64                            `json:"unit_price"`
	PurchaseValue      float64                            `json:"purchase_value"`
	TransportUnitPrice float64                            `json:"transport_unit_price"`
	TransportValue     float64                            `json:"transport_value"`
	TotalAmount        float64                            `json:"total_amount"`
	Expedition         string                             `json:"expedition"`
	DeliveryNumber     string                             `json:"delivery_number"`
}

type PurchaseSupplierSummaryDTO struct {
	TotalQty                float64 `json:"total_qty"`
	TotalPurchaseValue      float64 `json:"total_purchase_value"`
	TotalTransportValue     float64 `json:"total_transport_value"`
	TotalAmount             float64 `json:"total_amount"`
	TotalUnitPrice          float64 `json:"total_unit_price"`
	TotalTransportUnitPrice float64 `json:"total_transport_unit_price"`
}

type PurchaseSupplierDTO struct {
	Supplier *supplierDTO.SupplierRelationDTO `json:"supplier"`
	Rows     []PurchaseSupplierRowDTO         `json:"rows"`
	Summary  PurchaseSupplierSummaryDTO       `json:"summary"`
}

func formatDatePtr(t *time.Time) string {
	if t == nil || t.IsZero() {
		return ""
	}
	return t.Format("02-Jan-2006")
}

func ToPurchaseSupplierRowDTO(item *entity.PurchaseItem) PurchaseSupplierRowDTO {
	row := PurchaseSupplierRowDTO{
		ReceiveDate: formatDatePtr(item.ReceivedDate),
		Qty:         item.TotalQty,
		UnitPrice:   item.Price,
	}

	if item.Purchase != nil {
		row.PoDate = formatDatePtr(item.Purchase.PoDate)
		if item.Purchase.PoNumber != nil {
			row.PoNumber = *item.Purchase.PoNumber
		}
	}

	if item.Product != nil && item.Product.Id != 0 {
		product := productDTO.ToProductRelationDTO(*item.Product)
		row.Product = &product
	}

	if item.Warehouse != nil && item.Warehouse.Id != 0 {
		warehouse := warehouseDTO.ToWarehouseRelationDTO(*item.Warehouse)
		row.Warehouse = &warehouse
	}

	qty := row.Qty
	if qty < 0 {
		qty = 0
	}

	row.PurchaseValue = row.UnitPrice * qty

	var transportUnit float64
	var expeditionName string

	if item.ExpenseNonstock != nil {
		transportUnit = item.ExpenseNonstock.Price

		if item.ExpenseNonstock.Expense != nil &&
			item.ExpenseNonstock.Expense.Supplier != nil &&
			item.ExpenseNonstock.Expense.Supplier.Id != 0 {
			expSupplier := item.ExpenseNonstock.Expense.Supplier
			expeditionName = expSupplier.Name
		}
	}

	row.TransportUnitPrice = transportUnit
	row.TransportValue = transportUnit * qty
	row.TotalAmount = row.PurchaseValue + row.TransportValue

	if expeditionName == "" {
		row.Expedition = "-"
	} else {
		row.Expedition = expeditionName
	}

	if item.TravelNumber != nil && *item.TravelNumber != "" {
		row.DeliveryNumber = *item.TravelNumber
	} else {
		row.DeliveryNumber = "-"
	}

	return row
}

func ToPurchaseSupplierDTO(supplier entity.Supplier, items []entity.PurchaseItem) PurchaseSupplierDTO {
	var supplierDTORef *supplierDTO.SupplierRelationDTO
	if supplier.Id != 0 {
		mapped := supplierDTO.ToSupplierRelationDTO(supplier)
		supplierDTORef = &mapped
	}

	rows := make([]PurchaseSupplierRowDTO, 0, len(items))
	summary := PurchaseSupplierSummaryDTO{}

	for i := range items {
		row := ToPurchaseSupplierRowDTO(&items[i])
		rows = append(rows, row)

		summary.TotalQty += row.Qty
		summary.TotalPurchaseValue += row.PurchaseValue
		summary.TotalTransportValue += row.TransportValue
		summary.TotalAmount += row.TotalAmount

	}

	if summary.TotalQty > 0 {
		avg := summary.TotalPurchaseValue / summary.TotalQty
		summary.TotalUnitPrice = math.Round(avg)
	}

	if summary.TotalQty > 0 {
		avg := summary.TotalTransportValue / summary.TotalQty
		summary.TotalTransportUnitPrice = math.Round(avg)
	}

	return PurchaseSupplierDTO{
		Supplier: supplierDTORef,
		Rows:     rows,
		Summary:  summary,
	}
}
