package dto

import (
	"time"

	entity "gitlab.com/mbugroup/lti-api.git/internal/entities"
	approvalDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/approvals/dto"
	kandangDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/kandangs/dto"
	nonstockDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/nonstocks/dto"
	supplierDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/suppliers/dto"
)

// === DTO Structs ===

type RepportExpenseBaseDTO struct {
	Id              uint64                           `json:"id"`
	ReferenceNumber string                           `json:"reference_number"`
	PoNumber        string                           `json:"po_number"`
	Category        string                           `json:"category"`
	Notes           string                           `json:"notes"`
	Supplier        *supplierDTO.SupplierRelationDTO `json:"supplier,omitempty"`
	RealizationDate *time.Time                       `json:"realization_date,omitempty"`
	TransactionDate time.Time                        `json:"transaction_date"`
	CreatedAt       time.Time                        `json:"created_at"`
	UpdatedAt       time.Time                        `json:"updated_at"`
}

type RepportExpensePengajuanDTO struct {
	Id                    uint64                           `json:"id"`
	ExpenseId             *uint64                          `json:"expense_id,omitempty"`
	ProjectFlockKandangId *uint64                          `json:"project_flock_kandang_id,omitempty"`
	Qty                   float64                          `json:"qty"`
	Price                 float64                          `json:"price"`
	Notes                 string                           `json:"notes"`
	Nonstock              *nonstockDTO.NonstockRelationDTO `json:"nonstock,omitempty"`
	CreatedAt             time.Time                        `json:"created_at"`
}

type RepportExpenseRealisasiDTO struct {
	Id                *uint64                          `json:"id,omitempty"`
	ExpenseNonstockId *uint64                          `json:"expense_nonstock_id,omitempty"`
	Qty               float64                          `json:"qty"`
	Price             float64                          `json:"price"`
	Notes             string                           `json:"notes"`
	Nonstock          *nonstockDTO.NonstockRelationDTO `json:"nonstock,omitempty"`
	CreatedAt         time.Time                        `json:"created_at"`
}

type RepportExpenseListDTO struct {
	RepportExpenseBaseDTO
	Kandang        *kandangDTO.KandangRelationDTO   `json:"kandang,omitempty"`
	Pengajuan      RepportExpensePengajuanDTO       `json:"pengajuan"`
	Realisasi      RepportExpenseRealisasiDTO       `json:"realisasi"`
	TotalPengajuan float64                          `json:"total_pengajuan"`
	TotalRealisasi float64                          `json:"total_realisasi"`
	LatestApproval *approvalDTO.ApprovalRelationDTO `json:"latest_approval,omitempty"`
}

// === MAPPERS ===

func ToRepportExpenseBaseDTO(e *entity.Expense) RepportExpenseBaseDTO {
	var realizationDate *time.Time
	if !e.RealizationDate.IsZero() {
		realizationDate = &e.RealizationDate
	}

	var supplier *supplierDTO.SupplierRelationDTO
	if e.Supplier != nil && e.Supplier.Id != 0 {
		mapped := supplierDTO.ToSupplierRelationDTO(*e.Supplier)
		supplier = &mapped
	}

	return RepportExpenseBaseDTO{
		Id:              e.Id,
		ReferenceNumber: e.ReferenceNumber,
		PoNumber:        e.PoNumber,
		Category:        e.Category,
		Notes:           e.Notes,
		Supplier:        supplier,
		RealizationDate: realizationDate,
		TransactionDate: e.TransactionDate,
		CreatedAt:       e.CreatedAt,
		UpdatedAt:       e.UpdatedAt,
	}
}

func ToRepportExpensePengajuanDTO(ns *entity.ExpenseNonstock) RepportExpensePengajuanDTO {
	var nonstock *nonstockDTO.NonstockRelationDTO
	if ns.Nonstock != nil && ns.Nonstock.Id != 0 {
		mapped := nonstockDTO.ToNonstockRelationDTO(*ns.Nonstock)
		nonstock = &mapped
	}

	return RepportExpensePengajuanDTO{
		Id:                    ns.Id,
		ExpenseId:             ns.ExpenseId,
		ProjectFlockKandangId: ns.ProjectFlockKandangId,
		Qty:                   ns.Qty,
		Price:                 ns.Price,
		Notes:                 ns.Notes,
		Nonstock:              nonstock,
		CreatedAt:             ns.CreatedAt,
	}
}

func ToRepportExpenseRealisasiDTO(r *entity.ExpenseRealization) RepportExpenseRealisasiDTO {
	var nonstock *nonstockDTO.NonstockRelationDTO
	if r.ExpenseNonstock != nil && r.ExpenseNonstock.Nonstock != nil && r.ExpenseNonstock.Nonstock.Id != 0 {
		mapped := nonstockDTO.ToNonstockRelationDTO(*r.ExpenseNonstock.Nonstock)
		nonstock = &mapped
	}

	return RepportExpenseRealisasiDTO{
		Id:                r.ExpenseNonstockId,
		ExpenseNonstockId: r.ExpenseNonstockId,
		Qty:               r.Qty,
		Price:             r.Price,
		Notes:             r.Notes,
		Nonstock:          nonstock,
		CreatedAt:         r.CreatedAt,
	}
}

func ToRepportExpenseListDTO(baseDTO RepportExpenseBaseDTO, ns *entity.ExpenseNonstock, latestApproval *approvalDTO.ApprovalRelationDTO) RepportExpenseListDTO {
	var realisasi RepportExpenseRealisasiDTO
	if ns.Realization != nil {
		realisasi = ToRepportExpenseRealisasiDTO(ns.Realization)
	}

	totalPengajuan := ns.Qty * ns.Price
	totalRealisasi := float64(0)
	if ns.Realization != nil {
		totalRealisasi = ns.Realization.Qty * ns.Realization.Price
	}

	// Get kandang data at the main level
	var kandang *kandangDTO.KandangRelationDTO
	if ns.Kandang != nil && ns.Kandang.Id != 0 {
		mapped := kandangDTO.ToKandangRelationDTO(*ns.Kandang)
		kandang = &mapped
	}

	return RepportExpenseListDTO{
		RepportExpenseBaseDTO: baseDTO,
		Kandang:               kandang,
		Pengajuan:             ToRepportExpensePengajuanDTO(ns),
		Realisasi:             realisasi,
		TotalPengajuan:        totalPengajuan,
		TotalRealisasi:        totalRealisasi,
		LatestApproval:        latestApproval,
	}
}

func ToRepportExpenseListDTOs(realizations []entity.ExpenseRealization) []RepportExpenseListDTO {
	result := make([]RepportExpenseListDTO, 0, len(realizations))

	for _, realization := range realizations {
		if realization.ExpenseNonstock == nil || realization.ExpenseNonstock.Expense == nil {
			continue
		}

		expense := realization.ExpenseNonstock.Expense
		baseDTO := ToRepportExpenseBaseDTO(expense)

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

		// Create a temporary realization with the current realization data
		if realization.ExpenseNonstock.Realization == nil {
			realization.ExpenseNonstock.Realization = &realization
		}

		dto := ToRepportExpenseListDTO(baseDTO, realization.ExpenseNonstock, latestApproval)
		result = append(result, dto)
	}

	return result
}
