package dto

import (
	"time"

	entity "gitlab.com/mbugroup/lti-api.git/internal/entities"
	locationDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/locations/dto"
	productCategoryDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/product-categories/dto"
	uomDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/uoms/dto"
	userDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/users/dto"
)

// === DTO Structs ===

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

type ProductStockListDTO struct {
	Id                uint                                           `json:"id"`
	Name              string                                         `json:"name"`
	Brand             string                                         `json:"brand"`
	Sku               *string                                        `json:"sku,omitempty"`
	ProductPrice      float64                                        `json:"product_price"`
	SellingPrice      *float64                                       `json:"selling_price,omitempty"`
	Tax               *float64                                       `json:"tax,omitempty"`
	ExpiryPeriod      *int                                           `json:"expiry_period,omitempty"`
	Flags             []string                                       `json:"flags"`
	Uom               *uomDTO.UomRelationDTO                         `json:"uom,omitempty"`
	ProductCategory   *productCategoryDTO.ProductCategoryRelationDTO `json:"product_category,omitempty"`
	CreatedUser       *userDTO.UserRelationDTO                       `json:"created_user"`
	CreatedAt         time.Time                                      `json:"created_at"`
	UpdatedAt         time.Time                                      `json:"updated_at"`
	Suppliers         []SupplierDTO                                  `json:"suppliers,omitempty"`
	ProductWarehouses []ProductWarehouseDTO                          `json:"product_warehouses,omitempty"`
	TotalStock        float64                                        `json:"total_stock"`
}

type ProductStockDetailDTO struct {
	ProductStockListDTO
}

type SupplierDTO struct {
	Id       uint   `json:"id"`
	Name     string `json:"name"`
	Alias    string `json:"alias"`
	Category string `json:"category"`
}

type ProductWarehouseDTO struct {
	Id            uint                             `json:"id"`
	ProductId     uint                             `json:"product_id"`
	WarehouseId   uint                             `json:"warehouse_id"`
	WarehouseName string                           `json:"warehouse_name"`
	Location      *locationDTO.LocationRelationDTO `json:"location"`
	CurrentStock  float64                          `json:"current_stock"`
	StockLogs     []StockLogDetailDTO              `json:"stock_logs"`
}

type StockLogDetailDTO struct {
	Id                 uint                     `json:"id"`
	Increase           float64                  `json:"increase"`
	Decrease           float64                  `json:"decrease"`
	Stock              float64                  `json:"stock"`
	LoggableType       string                   `json:"loggable_type"`
	LoggableId         uint                     `json:"loggable_id"`
	Notes              *string                  `json:"notes"`
	ProductWarehouseId uint                     `json:"product_warehouse_id"`
	CreatedBy          uint                     `json:"created_by"`
	CreatedUser        *userDTO.UserRelationDTO `json:"created_user,omitempty"`
	CreatedAt          time.Time                `json:"created_at"`
}

// === Mapper Functions ===
func ToProductStockListDTO(e entity.Product) ProductStockListDTO {
	var createdUser *userDTO.UserRelationDTO
	if e.CreatedUser.Id != 0 {
		mapped := userDTO.ToUserRelationDTO(e.CreatedUser)
		createdUser = &mapped
	}

	var categoryRef *productCategoryDTO.ProductCategoryRelationDTO
	if e.ProductCategory.Id != 0 {
		mapped := productCategoryDTO.ToProductCategoryRelationDTO(e.ProductCategory)
		categoryRef = &mapped
	}

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

	var uomRef *uomDTO.UomRelationDTO
	if e.Uom.Id != 0 {
		mapped := uomDTO.ToUomRelationDTO(e.Uom)
		uomRef = &mapped
	}

	return ProductStockListDTO{
		Id:              e.Id,
		Name:            e.Name,
		Flags:           flags,
		Uom:             uomRef,
		Brand:           e.Brand,
		Sku:             e.Sku,
		ProductPrice:    e.ProductPrice,
		SellingPrice:    e.SellingPrice,
		Tax:             e.Tax,
		ExpiryPeriod:    e.ExpiryPeriod,
		CreatedAt:       e.CreatedAt,
		UpdatedAt:       e.UpdatedAt,
		CreatedUser:     createdUser,
		ProductCategory: categoryRef,
		Suppliers:       mapSupplierDTOs(e.ProductSuppliers),
		TotalStock:      calculateTotalStock(e.ProductWarehouses),
	}
}

func ToProductStockListDTOs(e []entity.Product) []ProductStockListDTO {
	result := make([]ProductStockListDTO, len(e))
	for i, r := range e {
		result[i] = ToProductStockListDTO(r)
	}
	return result
}

func ToProductStockDetailDTO(e entity.Product) ProductStockDetailDTO {
	base := ToProductStockListDTO(e)
	base.ProductWarehouses = mapProductWarehouseDTOs(e.ProductWarehouses)

	return ProductStockDetailDTO{
		ProductStockListDTO: base,
	}
}

// --- helpers ---

func mapSupplierDTOs(src []entity.ProductSupplier) []SupplierDTO {
	if len(src) == 0 {
		return nil
	}
	result := make([]SupplierDTO, 0, len(src))
	for _, ps := range src {
		if ps.Supplier.Id == 0 {
			continue
		}
		result = append(result, SupplierDTO{
			Id:       ps.Supplier.Id,
			Name:     ps.Supplier.Name,
			Alias:    ps.Supplier.Alias,
			Category: ps.Supplier.Category,
		})
	}
	return result
}

func mapProductWarehouseDTOs(src []entity.ProductWarehouse) []ProductWarehouseDTO {
	if len(src) == 0 {
		return []ProductWarehouseDTO{}
	}
	result := make([]ProductWarehouseDTO, 0, len(src))
	for _, pw := range src {
		dto := ProductWarehouseDTO{
			Id:           pw.Id,
			ProductId:    pw.ProductId,
			WarehouseId:  pw.WarehouseId,
			CurrentStock: pw.Quantity,
			StockLogs:    mapStockLogs(pw.StockLogs),
		}
		if pw.Warehouse.Id != 0 {
			dto.WarehouseName = pw.Warehouse.Name
			if pw.Warehouse.Location != nil {
				mapped := locationDTO.ToLocationRelationDTO(*pw.Warehouse.Location)
				dto.Location = &mapped
			}
		}
		result = append(result, dto)
	}
	return result
}

func mapStockLogs(src []entity.StockLog) []StockLogDetailDTO {
	if len(src) == 0 {
		return []StockLogDetailDTO{}
	}
	result := make([]StockLogDetailDTO, 0, len(src))
	for _, log := range src {
		var notes *string
		if log.Notes != "" {
			n := log.Notes
			notes = &n
		}

		result = append(result, StockLogDetailDTO{
			Id:                 log.Id,
			Increase:           log.Increase,
			Decrease:           log.Decrease,
			Stock:              log.Stock,
			LoggableType:       log.LoggableType,
			LoggableId:         log.LoggableId,
			Notes:              notes,
			ProductWarehouseId: log.ProductWarehouseId,
			CreatedBy:          log.CreatedBy,
			CreatedUser:        mapCreatedUser(log.CreatedUser),
			CreatedAt:          log.CreatedAt,
		})
	}
	return result
}

func mapCreatedUser(user *entity.User) *userDTO.UserRelationDTO {
	if user == nil || user.Id == 0 {
		return nil
	}
	mapped := userDTO.ToUserRelationDTO(*user)
	return &mapped
}

func calculateTotalStock(productWarehouses []entity.ProductWarehouse) float64 {
	var total float64
	for _, pw := range productWarehouses {
		total += pw.Quantity
	}
	return total
}
