/*
DESCRIPTION:
Any functions that are used internally by the use-case
*/
package prescription

import (
	em "simrs-vx/internal/domain/main-entities/medication"
	emei "simrs-vx/internal/domain/main-entities/medication-item"
	emi "simrs-vx/internal/domain/main-entities/medicine-mix"
	emmi "simrs-vx/internal/domain/main-entities/medicine-mix-item"
	e "simrs-vx/internal/domain/main-entities/prescription"
	epi "simrs-vx/internal/domain/main-entities/prescription-item"

	erc "simrs-vx/internal/domain/references/common"

	um "simrs-vx/internal/use-case/main-use-case/medication"
	umei "simrs-vx/internal/use-case/main-use-case/medication-item"
	umi "simrs-vx/internal/use-case/main-use-case/medicine-mix"
	ummi "simrs-vx/internal/use-case/main-use-case/medicine-mix-item"
	upi "simrs-vx/internal/use-case/main-use-case/prescription-item"

	pl "simrs-vx/pkg/logger"
	pu "simrs-vx/pkg/use-case-helper"

	"gorm.io/gorm"
)

func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.Prescription) {
	var inputSrc *e.CreateDto
	if inputT, ok := any(input).(*e.CreateDto); ok {
		inputSrc = inputT
		data.Status_Code = erc.DSCNew
	} else {
		inputTemp := any(input).(*e.UpdateDto)
		inputSrc = &inputTemp.CreateDto
	}

	data.Encounter_Id = inputSrc.Encounter_Id
	data.Doctor_Code = inputSrc.AuthInfo.Doctor_Code
	data.IssuedAt = inputSrc.IssuedAt
}

func createMedication(prescription_id uint, event *pl.Event, tx *gorm.DB) error {
	pl.SetLogInfo(event, nil, "started", "createMedication")

	prescription, err := ReadDetailData(e.ReadDetailDto{Id: prescription_id}, event, tx)
	if err != nil {
		return err
	}

	prescriptionItem, _, err := upi.ReadListData(epi.ReadListDto{FilterDto: epi.FilterDto{Prescription_Id: &prescription.Id}}, event, tx)
	if err != nil {
		return err
	}

	if len(prescriptionItem) == 0 {
		return nil
	}

	medicationCreate := em.CreateDto{
		Encounter_Id: prescription.Encounter_Id,
		IssuedAt:     pu.GetTimeNow(),
	}
	medication, err := um.CreateData(medicationCreate, event, tx)
	if err != nil {
		return err
	}

	for _, prescriptionItem := range prescriptionItem {
		if prescriptionItem.IsMix {
			medMix_id, err := createMedicineMixAndItem(*prescriptionItem.MedicineMix, event, tx)
			if err != nil {
				return err
			}
			prescriptionItem.MedicineMix_Id = medMix_id
		}
		err := createMedicationItem(medication.Id, prescriptionItem, event, tx)
		if err != nil {
			return err
		}
	}
	return nil
}

func createMedicineMixAndItem(input emi.MedicineMix, event *pl.Event, tx *gorm.DB) (*uint, error) {
	pl.SetLogInfo(event, nil, "started", "createMedicineMix")

	medicineMixCreate := emi.CreateDto{
		Name:     input.Name,
		Uom_Code: input.Uom_Code,
	}
	medicineMix, err := umi.CreateData(medicineMixCreate, event, tx)
	if err != nil {
		return nil, err
	}

	// recreate medicineMixItem with new medicineMix_id to keep medMixItem remain the same for prescriptionItem that is created
	for _, medicineMixItem := range input.MixItems {
		medicineMixItemCreate := emmi.CreateDto{
			MedicineMix_Id: &medicineMix.Id,
			Medicine_Code:  medicineMixItem.Medicine_Code,
			Dose:           medicineMixItem.Dose,
		}
		_, err := ummi.CreateData(medicineMixItemCreate, event, tx)
		if err != nil {
			return nil, err
		}

	}
	return &medicineMix.Id, nil
}

func createMedicationItem(medication_id uint, input epi.PrescriptionItem, event *pl.Event, tx *gorm.DB) error {
	pl.SetLogInfo(event, nil, "started", "createMedicationItem")

	medicationItemCreate := emei.CreateDto{
		Medication_Id:     &medication_id,
		IsMix:             input.IsMix,
		Medicine_Code:     input.Medicine_Code,
		MedicineMix_Id:    input.MedicineMix_Id,
		Frequency:         input.Frequency,
		Dose:              input.Dose,
		Usage:             input.Usage,
		Interval:          input.Interval,
		IntervalUnit_Code: input.IntervalUnit_Code,
		Quantity:          input.Quantity,
	}

	_, err := umei.CreateData(medicationItemCreate, event, tx)
	if err != nil {
		return err
	}

	return nil
}
