package dto

import (
	"time"

	entity "gitlab.com/mbugroup/lti-api.git/internal/entities"
	warehouseDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/warehouses/dto"
	userDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/users/dto"
)

type TransferRelationDTO struct {
	Id                   uint64                             `json:"id"`
	MovementNumber       string                             `json:"movement_number"`
	TransferReason       string                             `json:"transfer_reason"`
	TransferDate         string                             `json:"transfer_date"`
	SourceWarehouse      *warehouseDTO.WarehouseRelationDTO `json:"source_warehouse,omitempty"`
	DestinationWarehouse *warehouseDTO.WarehouseRelationDTO `json:"destination_warehouse,omitempty"`
}

type ProductSimpleDTO struct {
	Id   uint   `json:"id"`
	Name string `json:"name"`
}

type SupplierSimpleDTO struct {
	Id   uint   `json:"id"`
	Name string `json:"name"`
}

type DocumentDTO struct {
	Id   uint    `json:"id"`
	Path string  `json:"path"`
	Name string  `json:"name"`
	Ext  string  `json:"ext"`
	Size float64 `json:"size"`
}

type TransferListDTO struct {
	TransferRelationDTO
	CreatedUser *userDTO.UserRelationDTO `json:"created_user,omitempty"`
	CreatedAt   time.Time                `json:"created_at"`
	UpdatedAt   time.Time                `json:"updated_at"`
	Details     []TransferDetailItemDTO  `json:"details"`
	Deliveries  []TransferDeliveryDTO    `json:"deliveries"`
}

type TransferDetailDTO struct {
	TransferListDTO
	Details    []TransferDetailItemDTO `json:"details"`
	Deliveries []TransferDeliveryDTO   `json:"deliveries"`
}

type TransferDetailItemDTO struct {
	Id               uint64             `json:"id"`
	Product          ProductSimpleDTO   `json:"product"`
	Quantity         float64            `json:"quantity"`
	TransportPerItem *float64           `json:"transport_per_item,omitempty"` // Biaya ekspedisi per item
	ExpeditionVendor *SupplierSimpleDTO `json:"expedition_vendor,omitempty"`  // Vendor ekspedisi
}

type TransferDeliveryDTO struct {
	Id                uint64                    `json:"id"`
	Supplier          *SupplierSimpleDTO        `json:"supplier,omitempty"`
	VehiclePlate      string                    `json:"vehicle_plate"`
	DriverName        string                    `json:"driver_name"`
	DocumentNumber    string                    `json:"document_number"`
	ShippingCostItem  float64                   `json:"shipping_cost_item"`
	ShippingCostTotal float64                   `json:"shipping_cost_total"`
	Items             []TransferDeliveryItemDTO `json:"items"`
	Document          *DocumentDTO              `json:"document,omitempty"`
}

type TransferDeliveryItemDTO struct {
	Id                    uint64  `json:"id"`
	StockTransferDetailId uint64  `json:"stock_transfer_detail_id"`
	Quantity              float64 `json:"quantity"`
}

func ToTransferRelationDTO(e entity.StockTransfer) TransferRelationDTO {
	var sourceWarehouse *warehouseDTO.WarehouseRelationDTO
	if e.FromWarehouse != nil && e.FromWarehouse.Id != 0 {
		mapped := warehouseDTO.ToWarehouseRelationDTO(*e.FromWarehouse)
		sourceWarehouse = &mapped
	}
	var destinationWarehouse *warehouseDTO.WarehouseRelationDTO
	if e.ToWarehouse != nil && e.ToWarehouse.Id != 0 {
		mapped := warehouseDTO.ToWarehouseRelationDTO(*e.ToWarehouse)
		destinationWarehouse = &mapped
	}
	return TransferRelationDTO{
		Id:                   e.Id,
		MovementNumber:       e.MovementNumber,
		TransferReason:       e.Reason,
		TransferDate:         e.CreatedAt.Format("2006-01-02"),
		SourceWarehouse:      sourceWarehouse,
		DestinationWarehouse: destinationWarehouse,
	}
}

func ToTransferListDTO(e entity.StockTransfer) TransferListDTO {
	var createdUser *userDTO.UserRelationDTO
	if e.CreatedUser != nil {
		mapped := userDTO.ToUserRelationDTO(*e.CreatedUser)
		createdUser = &mapped
	}

	var details []TransferDetailItemDTO
	for _, d := range e.Details {
		detailDTO := TransferDetailItemDTO{
			Id: d.Id,
			Product: ProductSimpleDTO{
				Id:   d.Product.Id,
				Name: d.Product.Name,
			},
			Quantity: d.UsageQty + d.PendingQty, // Total actual quantity allocated
		}

		if d.ExpenseNonstock != nil {
			priceCopy := d.ExpenseNonstock.Price
			detailDTO.TransportPerItem = &priceCopy

			if d.ExpenseNonstock.Expense != nil && d.ExpenseNonstock.Expense.Supplier != nil && d.ExpenseNonstock.Expense.Supplier.Id != 0 {
				exp := d.ExpenseNonstock.Expense
				detailDTO.ExpeditionVendor = &SupplierSimpleDTO{
					Id:   exp.Supplier.Id,
					Name: exp.Supplier.Name,
				}
			}
		}

		details = append(details, detailDTO)
	}

	var deliveries []TransferDeliveryDTO
	for _, del := range e.Deliveries {
		var items []TransferDeliveryItemDTO
		for _, item := range del.Items {
			items = append(items, TransferDeliveryItemDTO{
				Id:                    item.Id,
				StockTransferDetailId: item.StockTransferDetailId,
				Quantity:              item.Quantity,
			})
		}

		var document *DocumentDTO
		if len(del.Documents) > 0 {
			doc := del.Documents[0] // Take first document
			document = &DocumentDTO{
				Id:   doc.Id,
				Path: doc.Path,
				Name: doc.Name,
				Ext:  doc.Ext,
				Size: doc.Size,
			}
		}

		var supplier *SupplierSimpleDTO
		if del.Supplier != nil {
			supplier = &SupplierSimpleDTO{
				Id:   del.Supplier.Id,
				Name: del.Supplier.Name,
			}
		}

		deliveries = append(deliveries, TransferDeliveryDTO{
			Id:                del.Id,
			Supplier:          supplier,
			VehiclePlate:      del.VehiclePlate,
			DriverName:        del.DriverName,
			DocumentNumber:    del.DocumentNumber,
			ShippingCostItem:  del.ShippingCostItem,
			ShippingCostTotal: del.ShippingCostTotal,
			Items:             items,
			Document:          document,
		})
	}

	return TransferListDTO{
		TransferRelationDTO: ToTransferRelationDTO(e),
		CreatedUser:         createdUser,
		CreatedAt:           e.CreatedAt,
		UpdatedAt:           e.UpdatedAt,
		Details:             details,
		Deliveries:          deliveries,
	}
}

func ToTransferListDTOs(e []entity.StockTransfer) []TransferListDTO {
	result := make([]TransferListDTO, len(e))
	for i, r := range e {
		result[i] = ToTransferListDTO(r)
	}
	return result
}

func ToTransferDetailDTO(e entity.StockTransfer) TransferDetailDTO {
	var details []TransferDetailItemDTO
	for _, d := range e.Details {
		detailDTO := TransferDetailItemDTO{
			Id: d.Id,
			Product: ProductSimpleDTO{
				Id:   d.Product.Id,
				Name: d.Product.Name,
			},
			Quantity: d.UsageQty + d.PendingQty, // Total actual quantity allocated
		}

		if d.ExpenseNonstock != nil {
			priceCopy := d.ExpenseNonstock.Price
			detailDTO.TransportPerItem = &priceCopy

			if d.ExpenseNonstock.Expense != nil && d.ExpenseNonstock.Expense.Supplier != nil && d.ExpenseNonstock.Expense.Supplier.Id != 0 {
				exp := d.ExpenseNonstock.Expense
				detailDTO.ExpeditionVendor = &SupplierSimpleDTO{
					Id:   exp.Supplier.Id,
					Name: exp.Supplier.Name,
				}
			}
		}

		details = append(details, detailDTO)
	}

	var deliveries []TransferDeliveryDTO
	for _, del := range e.Deliveries {
		var items []TransferDeliveryItemDTO
		for _, item := range del.Items {
			items = append(items, TransferDeliveryItemDTO{
				Id:                    item.Id,
				StockTransferDetailId: item.StockTransferDetailId,
				Quantity:              item.Quantity,
			})
		}

		var document *DocumentDTO
		if len(del.Documents) > 0 {
			doc := del.Documents[0] // Take first document
			document = &DocumentDTO{
				Id:   doc.Id,
				Path: doc.Path,
				Name: doc.Name,
				Ext:  doc.Ext,
				Size: doc.Size,
			}
		}

		var supplier *SupplierSimpleDTO
		if del.Supplier != nil {
			supplier = &SupplierSimpleDTO{
				Id:   del.Supplier.Id,
				Name: del.Supplier.Name,
			}
		}

		deliveries = append(deliveries, TransferDeliveryDTO{
			Id:                del.Id,
			Supplier:          supplier,
			VehiclePlate:      del.VehiclePlate,
			DriverName:        del.DriverName,
			DocumentNumber:    del.DocumentNumber,
			ShippingCostItem:  del.ShippingCostItem,
			ShippingCostTotal: del.ShippingCostTotal,
			Items:             items,
			Document:          document,
		})
	}

	return TransferDetailDTO{
		TransferListDTO: ToTransferListDTO(e),
		Details:         details,
		Deliveries:      deliveries,
	}
}
