package dto

import (
	"time"

	entity "gitlab.com/mbugroup/lti-api.git/internal/entities"
	approvalDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/approvals/dto"
	productWarehouseDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/inventory/product-warehouses/dto"
	kandangDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/kandangs/dto"
	projectFlockDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/production/project_flocks/dto"
	userDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/users/dto"
)

// === DTO Structs ===

type TransferLayingRelationDTO struct {
	Id                 uint       `json:"id"`
	TransferNumber     string     `json:"transfer_number"`
	TransferDate       time.Time  `json:"transfer_date"`
	EconomicCutoffDate *time.Time `json:"economic_cutoff_date,omitempty"`
	EffectiveMoveDate  *time.Time `json:"effective_move_date,omitempty"`
	ExecutedAt         *time.Time `json:"executed_at,omitempty"`
	Notes              string     `json:"notes"`
}

type ProjectFlockKandangWithKandangDTO struct {
	Id             uint                           `json:"id"`
	KandangId      uint                           `json:"kandang_id"`
	ProjectFlockId uint                           `json:"project_flock_id"`
	Kandang        *kandangDTO.KandangRelationDTO `json:"kandang,omitempty"`
}

type LayingTransferSourceDTO struct {
	SourceProjectFlockKandang *ProjectFlockKandangWithKandangDTO               `json:"source_project_flock_kandang,omitempty"`
	Qty                       float64                                          `json:"qty"`
	ProductWarehouse          *productWarehouseDTO.ProductWarehouseRelationDTO `json:"product_warehouse,omitempty"`
	Note                      string                                           `json:"note,omitempty"`
}

type LayingTransferTargetDTO struct {
	TargetProjectFlockKandang *ProjectFlockKandangWithKandangDTO               `json:"target_project_flock_kandang,omitempty"`
	Qty                       float64                                          `json:"qty"`
	ProductWarehouse          *productWarehouseDTO.ProductWarehouseRelationDTO `json:"product_warehouse,omitempty"`
	Note                      string                                           `json:"note,omitempty"`
}

type TransferLayingListDTO struct {
	TransferLayingRelationDTO
	FromProjectFlock *projectFlockDTO.ProjectFlockRelationDTO `json:"from_project_flock,omitempty"`
	ToProjectFlock   *projectFlockDTO.ProjectFlockRelationDTO `json:"to_project_flock,omitempty"`
	CreatedBy        uint                                     `json:"created_by"`
	CreatedUser      *userDTO.UserRelationDTO                 `json:"created_user,omitempty"`
	ExecutedBy       *uint                                    `json:"executed_by,omitempty"`
	ExecutedUser     *userDTO.UserRelationDTO                 `json:"executed_user,omitempty"`
	CreatedAt        time.Time                                `json:"created_at"`
	Approval         *approvalDTO.ApprovalRelationDTO         `json:"approval,omitempty"`
}

type TransferLayingDetailDTO struct {
	TransferLayingListDTO
	Sources  []LayingTransferSourceDTO        `json:"sources,omitempty"`
	Targets  []LayingTransferTargetDTO        `json:"targets,omitempty"`
	Approval *approvalDTO.ApprovalRelationDTO `json:"approval,omitempty"`
}

// === Available Quantity DTOs ===

type KandangAvailableQtyDTO struct {
	ProjectFlockKandangId uint    `json:"project_flock_kandang_id"`
	AvailableQty          float64 `json:"available_qty"`
}

type AvailableQtyForTransferDTO struct {
	ProjectFlockId   uint                     `json:"project_flock_id"`
	ProjectFlockCode string                   `json:"flock_name"`
	Category         string                   `json:"category"`
	Kandangs         []KandangAvailableQtyDTO `json:"kandangs"`
}

// === Max Target Quantity DTOs ===

type KandangMaxTargetQtyDTO struct {
	ProjectFlockKandangId uint    `json:"project_flock_kandang_id"`
	MaxTargetQty          float64 `json:"max_target_qty"`
}

type MaxTargetQtyForTransferDTO struct {
	ProjectFlockId       uint                     `json:"project_flock_id"`
	ProjectFlockKandangs []KandangMaxTargetQtyDTO `json:"project_flock_kandangs"`
}

// === Mapper Functions ===

func ToTransferLayingRelationDTO(e entity.LayingTransfer) TransferLayingRelationDTO {
	return TransferLayingRelationDTO{
		Id:                 e.Id,
		TransferNumber:     e.TransferNumber,
		TransferDate:       e.TransferDate,
		EconomicCutoffDate: e.EconomicCutoffDate,
		EffectiveMoveDate:  e.EffectiveMoveDate,
		ExecutedAt:         e.ExecutedAt,
		Notes:              e.Notes,
	}
}

func ToLayingTransferSourceDTO(source entity.LayingTransferSource) LayingTransferSourceDTO {
	// Tampilkan requested qty sebelum approve, consumed qty setelah approve
	var displayQty float64
	if source.UsageQty > 0 {
		// Sudah di-approve dan di-consume, tampilkan actual consumed quantity
		displayQty = source.UsageQty
	} else {
		// Belum di-approve, tampilkan requested quantity
		displayQty = source.RequestedQty
	}

	var pfkDTO *ProjectFlockKandangWithKandangDTO
	if source.SourceProjectFlockKandang != nil && source.SourceProjectFlockKandang.Id != 0 {
		pfkDTO = &ProjectFlockKandangWithKandangDTO{
			Id:             source.SourceProjectFlockKandang.Id,
			KandangId:      source.SourceProjectFlockKandang.KandangId,
			ProjectFlockId: source.SourceProjectFlockKandang.ProjectFlockId,
		}
		if source.SourceProjectFlockKandang.Kandang.Id != 0 {
			mapped := kandangDTO.ToKandangRelationDTO(source.SourceProjectFlockKandang.Kandang)
			pfkDTO.Kandang = &mapped
		}
	}

	var pwDTO *productWarehouseDTO.ProductWarehouseRelationDTO
	if source.ProductWarehouse != nil && source.ProductWarehouse.Id != 0 {
		mapped := productWarehouseDTO.ToProductWarehouseRelationDTO(*source.ProductWarehouse)
		pwDTO = &mapped
	}

	return LayingTransferSourceDTO{
		SourceProjectFlockKandang: pfkDTO,
		Qty:                       displayQty,
		ProductWarehouse:          pwDTO,
		Note:                      source.Note,
	}
}

func ToLayingTransferSourceDTOs(sources []entity.LayingTransferSource) []LayingTransferSourceDTO {
	if len(sources) == 0 {
		return []LayingTransferSourceDTO{}
	}
	result := make([]LayingTransferSourceDTO, len(sources))
	for i, s := range sources {
		result[i] = ToLayingTransferSourceDTO(s)
	}
	return result
}

func toLayingTransferSourceDTOsFromTransfer(e entity.LayingTransfer) []LayingTransferSourceDTO {
	if len(e.Sources) > 0 {
		return ToLayingTransferSourceDTOs(e.Sources)
	}
	if e.SourceProjectFlockKandangId == nil || *e.SourceProjectFlockKandangId == 0 {
		return []LayingTransferSourceDTO{}
	}

	displayQty := e.SourceRequestedQty
	if e.SourceUsageQty > 0 {
		displayQty = e.SourceUsageQty
	}

	pfkDTO := &ProjectFlockKandangWithKandangDTO{
		Id: *e.SourceProjectFlockKandangId,
	}
	if e.SourceProjectFlockKandang != nil && e.SourceProjectFlockKandang.Id != 0 {
		pfkDTO.KandangId = e.SourceProjectFlockKandang.KandangId
		pfkDTO.ProjectFlockId = e.SourceProjectFlockKandang.ProjectFlockId
		if e.SourceProjectFlockKandang.Kandang.Id != 0 {
			kandangMapped := kandangDTO.ToKandangRelationDTO(e.SourceProjectFlockKandang.Kandang)
			pfkDTO.Kandang = &kandangMapped
		}
	}

	var pwDTO *productWarehouseDTO.ProductWarehouseRelationDTO
	if e.SourceProductWarehouse != nil && e.SourceProductWarehouse.Id != 0 {
		mapped := productWarehouseDTO.ToProductWarehouseRelationDTO(*e.SourceProductWarehouse)
		pwDTO = &mapped
	}

	return []LayingTransferSourceDTO{
		{
			SourceProjectFlockKandang: pfkDTO,
			Qty:                       displayQty,
			ProductWarehouse:          pwDTO,
		},
	}
}

func ToLayingTransferTargetDTO(target entity.LayingTransferTarget) LayingTransferTargetDTO {
	var pfkDTO *ProjectFlockKandangWithKandangDTO
	if target.TargetProjectFlockKandang != nil && target.TargetProjectFlockKandang.Id != 0 {
		pfkDTO = &ProjectFlockKandangWithKandangDTO{
			Id:             target.TargetProjectFlockKandang.Id,
			KandangId:      target.TargetProjectFlockKandang.KandangId,
			ProjectFlockId: target.TargetProjectFlockKandang.ProjectFlockId,
		}
		if target.TargetProjectFlockKandang.Kandang.Id != 0 {
			mapped := kandangDTO.ToKandangRelationDTO(target.TargetProjectFlockKandang.Kandang)
			pfkDTO.Kandang = &mapped
		}
	}

	var pwDTO *productWarehouseDTO.ProductWarehouseRelationDTO
	if target.ProductWarehouse != nil && target.ProductWarehouse.Id != 0 {
		mapped := productWarehouseDTO.ToProductWarehouseRelationDTO(*target.ProductWarehouse)
		pwDTO = &mapped
	}

	return LayingTransferTargetDTO{
		TargetProjectFlockKandang: pfkDTO,
		Qty:                       target.TotalQty,
		ProductWarehouse:          pwDTO,
		Note:                      target.Note,
	}
}

func ToLayingTransferTargetDTOs(targets []entity.LayingTransferTarget) []LayingTransferTargetDTO {
	if len(targets) == 0 {
		return []LayingTransferTargetDTO{}
	}
	result := make([]LayingTransferTargetDTO, len(targets))
	for i, t := range targets {
		result[i] = ToLayingTransferTargetDTO(t)
	}
	return result
}

func ToTransferLayingListDTO(e entity.LayingTransfer) TransferLayingListDTO {
	var createdUser *userDTO.UserRelationDTO
	if e.CreatedUser != nil && e.CreatedUser.Id != 0 {
		mapped := userDTO.ToUserRelationDTO(*e.CreatedUser)
		createdUser = &mapped
	}

	var executedUser *userDTO.UserRelationDTO
	if e.ExecutedUser != nil && e.ExecutedUser.Id != 0 {
		mapped := userDTO.ToUserRelationDTO(*e.ExecutedUser)
		executedUser = &mapped
	}

	var approval *approvalDTO.ApprovalRelationDTO
	if e.LatestApproval != nil {
		mapped := approvalDTO.ToApprovalDTO(*e.LatestApproval)
		approval = &mapped
	}

	// Build from project flock DTO
	var fromProjectFlock *projectFlockDTO.ProjectFlockRelationDTO
	if e.FromProjectFlock != nil && e.FromProjectFlock.Id != 0 {
		fromProjectFlock = &projectFlockDTO.ProjectFlockRelationDTO{
			Id:        e.FromProjectFlock.Id,
			FlockName: e.FromProjectFlock.FlockName,
		}
	}

	var toProjectFlock *projectFlockDTO.ProjectFlockRelationDTO
	if e.ToProjectFlock != nil && e.ToProjectFlock.Id != 0 {
		toProjectFlock = &projectFlockDTO.ProjectFlockRelationDTO{
			Id:        e.ToProjectFlock.Id,
			FlockName: e.ToProjectFlock.FlockName,
		}
	}

	return TransferLayingListDTO{
		TransferLayingRelationDTO: ToTransferLayingRelationDTO(e),
		FromProjectFlock:          fromProjectFlock,
		ToProjectFlock:            toProjectFlock,
		CreatedBy:                 e.CreatedBy,
		CreatedUser:               createdUser,
		ExecutedBy:                e.ExecutedBy,
		ExecutedUser:              executedUser,
		CreatedAt:                 e.CreatedAt,
		Approval:                  approval,
	}
}

func ToTransferLayingDetailDTO(e entity.LayingTransfer, approvals []entity.Approval) TransferLayingDetailDTO {
	var latestApproval *approvalDTO.ApprovalRelationDTO

	// Prioritas: e.LatestApproval > approvals slice
	approvalToMap := e.LatestApproval
	if approvalToMap == nil && len(approvals) > 0 {
		approvalToMap = &approvals[len(approvals)-1]
	}

	if approvalToMap != nil {
		mapped := approvalDTO.ToApprovalDTO(*approvalToMap)
		latestApproval = &mapped
	}

	return TransferLayingDetailDTO{
		TransferLayingListDTO: ToTransferLayingListDTO(e),
		Sources:               toLayingTransferSourceDTOsFromTransfer(e),
		Targets:               ToLayingTransferTargetDTOs(e.Targets),
		Approval:              latestApproval,
	}
}

func ToTransferLayingDetailDTOWithSingleApproval(e entity.LayingTransfer, approval *entity.Approval) TransferLayingDetailDTO {
	var mappedApproval *approvalDTO.ApprovalRelationDTO

	// Prioritas: e.LatestApproval > approval parameter
	approvalToMap := e.LatestApproval
	if approvalToMap == nil && approval != nil {
		approvalToMap = approval
	}

	if approvalToMap != nil {
		mapped := approvalDTO.ToApprovalDTO(*approvalToMap)
		mappedApproval = &mapped
	}

	return TransferLayingDetailDTO{
		TransferLayingListDTO: ToTransferLayingListDTO(e),
		Sources:               toLayingTransferSourceDTOsFromTransfer(e),
		Targets:               ToLayingTransferTargetDTOs(e.Targets),
		Approval:              mappedApproval,
	}
}

func ToTransferLayingListDTOs(items []entity.LayingTransfer) []TransferLayingListDTO {
	result := make([]TransferLayingListDTO, len(items))
	for i, item := range items {
		result[i] = ToTransferLayingListDTO(item)
	}
	return result
}

func ToKandangMaxTargetQtyDTO(pfkId uint, maxTargetQTY float64) KandangMaxTargetQtyDTO {
	return KandangMaxTargetQtyDTO{
		ProjectFlockKandangId: uint(pfkId),
		MaxTargetQty:          maxTargetQTY,
	}
}

func ToMaxTargetQtyForTransferDTO(pfId uint, kandangs []KandangMaxTargetQtyDTO) MaxTargetQtyForTransferDTO {
	return MaxTargetQtyForTransferDTO{
		ProjectFlockId:       pfId,
		ProjectFlockKandangs: kandangs,
	}
}
