package dto

import (
	"time"

	"gitlab.com/mbugroup/lti-api.git/internal/config"
	entity "gitlab.com/mbugroup/lti-api.git/internal/entities"
	areaRelationDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/areas/dto"
	flockRelationDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/flocks/dto"
	kandangRelationDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/kandangs/dto"
	locationRelationDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/locations/dto"
	productDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/products/dto"
	warehouseDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/warehouses/dto"
	pfutils "gitlab.com/mbugroup/lti-api.git/internal/modules/production/project_flocks/utils"
	userRelationDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/users/dto"
	"gitlab.com/mbugroup/lti-api.git/internal/utils"
)

// === DTO Structs (ordered) ===

type ProductWarehouseDTO struct {
	Id        uint                               `json:"id"`
	Product   *productDTO.ProductRelationDTO     `json:"product,omitempty"`
	Warehouse *warehouseDTO.WarehouseRelationDTO `json:"warehouse,omitempty"`
}

type ChickinRelationDTO struct {
	Id                    uint                 `json:"id"`
	ProjectFlockKandangId uint                 `json:"project_flock_kandang_id"`
	ChickInDate           time.Time            `json:"chick_in_date"`
	ProductWarehouseId    uint                 `json:"product_warehouse_id"`
	ProductWarehouse      *ProductWarehouseDTO `json:"product_warehouse,omitempty"`
	UsageQty              float64              `json:"usage_qty"`
	PendingUsageQty       float64              `json:"pending_usage_qty"`
	Notes                 string               `json:"notes"`
}

type ProjectFlockDTO struct {
	Id          uint                                     `json:"id"`
	Period      int                                      `json:"period"`
	Category    string                                   `json:"category"`
	Flock       *flockRelationDTO.FlockRelationDTO       `json:"flock"`
	Area        *areaRelationDTO.AreaRelationDTO         `json:"area"`
	StandardFcr *float64                                 `json:"standard_fcr"`
	Location    *locationRelationDTO.LocationRelationDTO `json:"location"`
}

type ProjectFlockKandangDTO struct {
	Id           uint                                   `json:"id"`
	ProjectFlock *ProjectFlockDTO                       `json:"project_flock"`
	Kandang      *kandangRelationDTO.KandangRelationDTO `json:"kandang"`
}

// gunakan base DTO dari package users

type ChickinSimpleDTO struct {
	Id                    uint      `json:"id"`
	ProjectFlockKandangId uint      `json:"project_flock_kandang_id"`
	ChickInDate           time.Time `json:"chick_in_date"`
	ProductWarehouseId    uint      `json:"product_warehouse_id"`
	UsageQty              float64   `json:"usage_qty"`
	PendingUsageQty       float64   `json:"pending_usage_qty"`
	Notes                 string    `json:"notes"`
	CreatedBy             uint      `json:"created_by"`
}

type ChickinListDTO struct {
	ChickinRelationDTO
	CreatedUser *userRelationDTO.UserRelationDTO `json:"created_user"`
	CreatedAt   time.Time                        `json:"created_at"`
	UpdatedAt   time.Time                        `json:"updated_at"`
}

type ChickinDetailDTO struct {
	Id                    uint                             `json:"id"`
	ProjectFlockKandangId uint                             `json:"project_flock_kandang_id"`
	ChickInDate           time.Time                        `json:"chick_in_date"`
	ProductWarehouseId    uint                             `json:"product_warehouse_id"`
	UsageQty              float64                          `json:"usage_qty"`
	PendingUsageQty       float64                          `json:"pending_usage_qty"`
	Notes                 string                           `json:"notes"`
	CreatedBy             uint                             `json:"created_by"`
	CreatedUser           *userRelationDTO.UserRelationDTO `json:"created_user"`
	CreatedAt             time.Time                        `json:"created_at"`
	UpdatedAt             time.Time                        `json:"updated_at"`
}

// === Mapper Functions (ordered) ===

func ToFlockDTO(e entity.Flock) flockRelationDTO.FlockRelationDTO {
	return flockRelationDTO.ToFlockRelationDTO(e)
}

func ToKandangDTO(e entity.Kandang) kandangRelationDTO.KandangRelationDTO {
	return kandangRelationDTO.ToKandangRelationDTO(e)
}
func ToAreaDTO(e entity.Area) areaRelationDTO.AreaRelationDTO {
	return areaRelationDTO.ToAreaRelationDTO(e)
}

func ToLocationDTO(e entity.Location) locationRelationDTO.LocationRelationDTO {
	return locationRelationDTO.ToLocationRelationDTO(e)
}

func ToUserRelationDTO(e entity.User) userRelationDTO.UserRelationDTO {
	return userRelationDTO.ToUserRelationDTO(e)
}

func ToProjectFlockDTO(pfk entity.ProjectFlockKandang) ProjectFlockDTO {
	e := pfk.ProjectFlock
	var flock *flockRelationDTO.FlockRelationDTO
	if base := pfutils.DeriveBaseName(e.FlockName); base != "" {
		summary := flockRelationDTO.FlockRelationDTO{Id: 0, Name: base}
		flock = &summary
	}
	var area *areaRelationDTO.AreaRelationDTO
	if e.Area.Id != 0 {
		mapped := areaRelationDTO.ToAreaRelationDTO(e.Area)
		area = &mapped
	}
	var location *locationRelationDTO.LocationRelationDTO
	if e.Location.Id != 0 {
		mapped := locationRelationDTO.ToLocationRelationDTO(e.Location)
		location = &mapped
	}
	return ProjectFlockDTO{
		Id:          e.Id,
		Period:      pfk.Period,
		Category:    e.Category,
		Flock:       flock,
		Area:        area,
		StandardFcr: resolveProjectFlockStandardFcr(e),
		Location:    location,
	}
}

func ToProjectFlockKandangDTO(e entity.ProjectFlockKandang) ProjectFlockKandangDTO {
	var pf *ProjectFlockDTO
	if e.ProjectFlock.Id != 0 {
		mapped := ToProjectFlockDTO(e)
		pf = &mapped
	}
	var kandang *kandangRelationDTO.KandangRelationDTO
	if e.Kandang.Id != 0 {
		mapped := kandangRelationDTO.ToKandangRelationDTO(e.Kandang)
		kandang = &mapped
	}
	return ProjectFlockKandangDTO{
		Id:           e.Id,
		ProjectFlock: pf,
		Kandang:      kandang,
	}
}

func ToChickinRelationDTO(e entity.ProjectChickin) ChickinRelationDTO {
	var projectFlockKandangId uint
	// Check if ProjectFlockKandang relation is loaded
	if e.ProjectFlockKandang != nil && e.ProjectFlockKandang.Id != 0 {
		projectFlockKandangId = e.ProjectFlockKandang.Id
	} else if e.ProjectFlockKandangId != 0 {
		// If relation is not loaded but ID is available, use the ID
		projectFlockKandangId = e.ProjectFlockKandangId
	}

	var productWarehouse *ProductWarehouseDTO
	if e.ProductWarehouse != nil && e.ProductWarehouse.Id != 0 {
		productWarehouse = toProductWarehouseDTO(e.ProductWarehouse)
	}

	return ChickinRelationDTO{
		Id:                    e.Id,
		ProjectFlockKandangId: projectFlockKandangId,
		ChickInDate:           e.ChickInDate,
		ProductWarehouseId:    e.ProductWarehouseId,
		ProductWarehouse:      productWarehouse,
		UsageQty:              e.UsageQty,
		PendingUsageQty:       e.PendingUsageQty,
		Notes:                 e.Notes,
	}
}

func ToChickinSimpleDTO(e entity.ProjectChickin) ChickinSimpleDTO {
	return ChickinSimpleDTO{
		Id:                    e.Id,
		ProjectFlockKandangId: e.ProjectFlockKandangId,
		ChickInDate:           e.ChickInDate,
		ProductWarehouseId:    e.ProductWarehouseId,
		UsageQty:              e.UsageQty,
		PendingUsageQty:       e.PendingUsageQty,
		Notes:                 e.Notes,
		CreatedBy:             e.CreatedBy,
	}
}

func ToChickinListDTO(e entity.ProjectChickin) ChickinListDTO {
	var createdUser *userRelationDTO.UserRelationDTO
	if e.CreatedUser != nil && e.CreatedUser.Id != 0 {
		mapped := userRelationDTO.ToUserRelationDTO(*e.CreatedUser)
		createdUser = &mapped
	}
	return ChickinListDTO{
		ChickinRelationDTO: ToChickinRelationDTO(e),
		CreatedUser:        createdUser,
		CreatedAt:          e.CreatedAt,
		UpdatedAt:          e.UpdatedAt,
	}
}

func ToChickinListDTOs(e []entity.ProjectChickin) []ChickinListDTO {
	result := make([]ChickinListDTO, len(e))
	for i, r := range e {
		result[i] = ToChickinListDTO(r)
	}
	return result
}

func resolveProjectFlockStandardFcr(e entity.ProjectFlock) *float64 {
	if e.ProductionStandard.Id == 0 || len(e.ProductionStandard.ProductionStandardDetails) == 0 {
		return nil
	}
	week := 1
	if e.Category == string(utils.ProjectFlockCategoryLaying) {
		week = config.LayingWeekStart()
	}
	for _, detail := range e.ProductionStandard.ProductionStandardDetails {
		if detail.Week == week && detail.StandardFCR != nil {
			return detail.StandardFCR
		}
	}
	return nil
}

func ToChickinSimpleDTOs(e []entity.ProjectChickin) []ChickinSimpleDTO {
	result := make([]ChickinSimpleDTO, len(e))
	for i, r := range e {
		result[i] = ToChickinSimpleDTO(r)
	}
	return result
}

func ToChickinDetailDTO(e entity.ProjectChickin) ChickinDetailDTO {
	var createdUser *userRelationDTO.UserRelationDTO
	if e.CreatedUser != nil && e.CreatedUser.Id != 0 {
		mapped := userRelationDTO.ToUserRelationDTO(*e.CreatedUser)
		createdUser = &mapped
	}

	return ChickinDetailDTO{
		Id:                    e.Id,
		ProjectFlockKandangId: e.ProjectFlockKandangId,
		ChickInDate:           e.ChickInDate,
		ProductWarehouseId:    e.ProductWarehouseId,
		UsageQty:              e.UsageQty,
		PendingUsageQty:       e.PendingUsageQty,
		Notes:                 e.Notes,
		CreatedBy:             e.CreatedBy,
		CreatedUser:           createdUser,
		CreatedAt:             e.CreatedAt,
		UpdatedAt:             e.UpdatedAt,
	}
}

func ToChickinDetailDTOs(e []entity.ProjectChickin) []ChickinDetailDTO {
	result := make([]ChickinDetailDTO, len(e))
	for i, r := range e {
		result[i] = ToChickinDetailDTO(r)
	}
	return result
}

// === Helper Functions ===

// ToProductWarehouseDTO adalah exported helper untuk mapping ProductWarehouse (shared logic)
func ToProductWarehouseDTO(pw *entity.ProductWarehouse) *ProductWarehouseDTO {
	if pw == nil {
		return nil
	}

	product := productDTO.ToProductRelationDTO(pw.Product)
	warehouse := warehouseDTO.ToWarehouseRelationDTO(pw.Warehouse)

	return &ProductWarehouseDTO{
		Id:        pw.Id,
		Product:   &product,
		Warehouse: &warehouse,
	}
}

func toProductWarehouseDTO(pw *entity.ProductWarehouse) *ProductWarehouseDTO {
	return ToProductWarehouseDTO(pw)
}
