package encounter

import (
	// std
	"time"

	// internal - lib
	pa "simrs-vx/internal/lib/auth"

	// internal - domain - base-entities
	ecore "simrs-vx/internal/domain/base-entities/core"

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

	// internal - domain - main-entities
	evs "simrs-vx/internal/domain/bpjs-entities/vclaim-sep"
	eam "simrs-vx/internal/domain/main-entities/ambulatory"
	ea "simrs-vx/internal/domain/main-entities/appointment"
	edc "simrs-vx/internal/domain/main-entities/death-cause"
	ed "simrs-vx/internal/domain/main-entities/doctor"
	eem "simrs-vx/internal/domain/main-entities/emergency"
	ee "simrs-vx/internal/domain/main-entities/employee"
	eed "simrs-vx/internal/domain/main-entities/encounter-document"
	eip "simrs-vx/internal/domain/main-entities/inpatient"
	eir "simrs-vx/internal/domain/main-entities/internal-reference"
	en "simrs-vx/internal/domain/main-entities/nurse"
	ep "simrs-vx/internal/domain/main-entities/patient"
	er "simrs-vx/internal/domain/main-entities/rehab/base"
	es "simrs-vx/internal/domain/main-entities/specialist"
	ess "simrs-vx/internal/domain/main-entities/subspecialist"
	eu "simrs-vx/internal/domain/main-entities/unit"
)

type CreateDto struct {
	Patient_Id              *uint                    `json:"patient_id"`
	RegisteredAt            *time.Time               `json:"registeredAt"`
	Class_Code              ere.EncounterClassCode   `json:"class_code" validate:"maxLength=10"`
	SubClass_Code           *string                  `json:"subClass_code" validate:"maxLength=10"` // for sub
	Infra_Code              *string                  `json:"infra_code"`                            // for inpatient
	Unit_Code               *string                  `json:"unit_code"`
	Specialist_Code         *string                  `json:"specialist_code"`
	Subspecialist_Code      *string                  `json:"subspecialist_code"`
	VisitDate               time.Time                `json:"visitDate"`
	PaymentMethod_Code      ere.AllPaymentMethodCode `json:"paymentMethod_code" gorm:"size:10"`
	InsuranceCompany_Code   *string                  `json:"insuranceCompany_code"`
	Member_Number           *string                  `json:"member_number" validate:"maxLength=20"`
	Ref_Number              *string                  `json:"ref_number" validate:"maxLength=20"`
	Trx_Number              *string                  `json:"trx_number" validate:"maxLength=20"`
	Appointment_Doctor_Code *string                  `json:"appointment_doctor_code"`
	Adm_Employee_Id         *uint                    `json:"-"`
	Responsible_Doctor_Code *string                  `json:"responsible_doctor_code"`
	RefSource_Name          *string                  `json:"refSource_name" validate:"maxLength=100"`
	Appointment_Id          *uint                    `json:"appointment_id"`
	RefTypeCode             ere.RefTypeCode          `json:"refTypeCode"`
	NewStatus               bool                     `json:"newStatus"`
	VclaimReference         *TRujukan                `json:"vclaimReference"`

	Id                 uint              `json:"-"`
	RecentEncounterAdm *Encounter        `json:"-"` // if subClass_Code is rehab
	VisitMode_Code     ere.VisitModeCode `json:"-"` // if subClass_Code is rehab

	pa.AuthInfo
}

type TRujukan struct {
	NoSep        string `json:"noSep"` // Surat Eligibilitas Peserta
	TglRujukan   string `json:"tglRujukan"`
	PpkDirujuk   string `json:"ppkDirujuk"`   // PPK (Provider Pelayanan Kesehatan) -> kode RS tujuan
	JnsPelayanan string `json:"jnsPelayanan"` // Jenis pelayanan yang dimintakan; 1 = RawatInap; 2 = RawatJalan
	Catatan      string `json:"catatan"`
	DiagRujukan  string `json:"diagRujukan"` // Kode Diagnosa
	TipeRujukan  string `json:"tipeRujukan"` // 0 = Rujukan Penuh; 1 = Rujukan Partial (hanya untuk tindakan tertentu); 2 = Balik (dikembalikan ke faskes asal)
	PoliRujukan  string `json:"poliRujukan"` // Kode Poli Tujuan
	User         string `json:"user"`        // user yang membuat rujukan
}

type ReadListDto struct {
	FilterDto
	Includes           string `json:"includes"`
	Pagination         ecore.Pagination
	Patient_Identifier *string `json:"patient-identifier"`
	StartDate          *string `json:"start-date"`
	EndDate            *string `json:"end-date"`
	PaymentMethod_Code *string `json:"paymentMethod-code"`
	Status_Code        *string `json:"status-code"`
	Unit_Code          *string `json:"unit-code"`

	pa.AuthInfo
}

type FilterDto struct {
	Patient_Id                *uint                   `json:"patient-id"`
	Patient                   *ep.Patient             `json:"patient,omitempty"`
	RegisteredAt              *time.Time              `json:"registeredAt"`
	Class_Code                ere.EncounterClassCode  `json:"class-code" validate:"maxLength=10"`
	Specialist_Code           *string                 `json:"specialist-code"`
	Subspecialist_Code        *string                 `json:"subspecialist-code"`
	VisitDate                 time.Time               `json:"visitDate"`
	Appoinment_Doctor_Code    *string                 `json:"appointment-doctor-code"`
	Responsible_Doctor_Code   *string                 `json:"responsible-doctor-code"`
	DischargeMethod_Code      ere.DischargeMethodCode `json:"dischargeMethod-code" validate:"maxLength=10"`
	RefSource_Name            *string                 `json:"refSource-name" validate:"maxLength=100"`
	Appointment_Id            *uint                   `json:"appointment-id"`
	EarlyEducation            *string                 `json:"earlyEducation"`
	MedicalDischargeEducation *string                 `json:"medicalDischargeEducation"`
	AdmDischargeEducation     *string                 `json:"admDischargeEducation"`
	DischargeReason           *string                 `json:"dischargeReason"`
}

type ReadDetailDto struct {
	Id       uint   `json:"id"`
	Includes string `json:"includes"`
}

type UpdateDto struct {
	Id uint `json:"id"`
	CreateDto
}

type UpdateStatusDto struct {
	Id         uint               `json:"id"`
	StatusCode erc.DataStatusCode `json:"status_code"`

	pa.AuthInfo
}

type DeleteDto struct {
	Id uint `json:"id"`

	pa.AuthInfo
}

type MetaDto struct {
	PageNumber int `json:"page_number"`
	PageSize   int `json:"page_size"`
	Count      int `json:"count"`
}
type DischargeDto struct {
	Id                        uint                     `json:"id"`
	Discharge_Method_Code     *ere.DischargeMethodCode `json:"discharge_method_code" validate:"maxLength=16"`
	EarlyEducation            *string                  `json:"earlyEducation"`
	MedicalDischargeEducation *string                  `json:"medicalDischargeEducation"`
	AdmDischargeEducation     *string                  `json:"admDischargeEducation"`
	DischargeReason           *string                  `json:"dischargeReason"`
	DeathCause                *string                  `json:"deathCause"`

	pa.AuthInfo
}

type CheckinDto struct {
	Id                      uint       `json:"id"`
	Responsible_Doctor_Code *string    `json:"responsible_doctor_code"`
	Responsible_Nurse_Code  *string    `json:"responsible_nurse_code"`
	StartedAt               *time.Time `json:"startedAt"`
	FinishedAt              *time.Time `json:"finishedAt"`

	pa.AuthInfo
}

type SwitchUnitDto struct {
	Id                 uint                `json:"id"`
	PolySwitchCode     *ere.PolySwitchCode `json:"polySwitchCode"`
	InternalReferences *[]eir.CreateDto    `json:"internalReferences" validate:"required"`

	Src_Doctor_Code *string `json:"-"`
	Src_Nurse_Code  *string `json:"-"`
	pa.AuthInfo
}

type ApproveCancelUnitDto struct {
	Id                    uint    `json:"id"`
	InternalReferences_Id uint    `json:"internalReferences_id" validate:"required"`
	Dst_Doctor_Code       *string `json:"dst_doctor_code"`

	pa.AuthInfo
}

type ResponseDto struct {
	ecore.Main
	Patient_Id                *uint                    `json:"patient_id"`
	Patient                   *ep.Patient              `json:"patient,omitempty"`
	RegisteredAt              *time.Time               `json:"registeredAt"`
	Class_Code                ere.EncounterClassCode   `json:"class_code"`
	Unit_Code                 *string                  `json:"unit_code"`
	Specialist_Code           *string                  `json:"specialist_code"`
	Specialist                *es.Specialist           `json:"specialist,omitempty"`
	Subspecialist_Code        *string                  `json:"subspecialist_code"`
	Subspecialist             *ess.Subspecialist       `json:"subspecialist,omitempty"`
	Unit                      *eu.Unit                 `json:"unit,omitempty"`
	VisitDate                 time.Time                `json:"visitDate"`
	PaymentMethod_Code        ere.AllPaymentMethodCode `json:"paymentMethod_code"`
	InsuranceCompany_Code     *string                  `json:"insuranceCompany_code"`
	Member_Number             *string                  `json:"member_number"`
	Ref_Number                *string                  `json:"ref_number"`
	Trx_Number                *string                  `json:"trx_number"`
	Appointment_Doctor_Code   *string                  `json:"appointment_doctor_code"`
	Appointment_Doctor        *ed.Doctor               `json:"appointment_doctor,omitempty"`
	Responsible_Doctor_Code   *string                  `json:"responsible_doctor_code"`
	Responsible_Doctor        *ed.Doctor               `json:"responsible_doctor,omitempty"`
	Adm_Employee_Id           *uint                    `json:"adm_employee_id"`
	Adm_Employee              *ee.Employee             `json:"adm_employee,omitempty"`
	Discharge_Method_Code     *ere.DischargeMethodCode `json:"discharge_method_code"`
	RefSource_Name            *string                  `json:"refSource_name"`
	Appointment_Id            *uint                    `json:"appointment_id"`
	Appointment               *ea.Appointment          `json:"appointment,omitempty"`
	EarlyEducation            *string                  `json:"earlyEducation"`
	MedicalDischargeEducation *string                  `json:"medicalDischargeEducation"`
	AdmDischargeEducation     *string                  `json:"admDischargeEducation"`
	DischargeReason           *string                  `json:"dischargeReason"`
	Status_Code               erc.DataStatusCode       `json:"status_code"`
	VclaimSep                 *evs.VclaimSep           `json:"vclaimSep,omitempty"`
	StartedAt                 *time.Time               `json:"startedAt"`
	FinishedAt                *time.Time               `json:"finishedAt"`
	Discharge_Date            *time.Time               `json:"discharge_date"`
	InternalReferences        *[]eir.InternalReference `json:"internalReferences,omitempty"`
	DeathCause                *edc.DeathCause          `json:"deathCause,omitempty"`
	NewStatus                 bool                     `json:"newStatus"`
	Ambulatory                *eam.Ambulatory          `json:"ambulatory,omitempty"`
	Emergency                 *eem.Emergency           `json:"emergency,omitempty"`
	Inpatient                 *eip.Inpatient           `json:"inpatient,omitempty"`
	Rehab                     *er.Basic                `json:"rehab,omitempty"`
	RehabChildren             *[]er.Basic              `json:"rehabChildren,omitempty"`
	EncounterDocuments        *[]eed.EncounterDocument `json:"encounterDocuments,omitempty"`
	Responsible_Nurse_Code    *string                  `json:"responsible_nurse_code"`
	Responsible_Nurse         *en.Nurse                `json:"responsible_nurse,omitempty"`
}

func (d Encounter) ToResponse() ResponseDto {
	resp := ResponseDto{
		Patient_Id:                d.Patient_Id,
		Patient:                   d.Patient,
		RegisteredAt:              d.RegisteredAt,
		Class_Code:                d.Class_Code,
		Unit_Code:                 d.Unit_Code,
		Unit:                      d.Unit,
		Specialist_Code:           d.Specialist_Code,
		Specialist:                d.Specialist,
		Subspecialist_Code:        d.Subspecialist_Code,
		Subspecialist:             d.Subspecialist,
		VisitDate:                 d.VisitDate,
		PaymentMethod_Code:        d.PaymentMethod_Code,
		InsuranceCompany_Code:     d.InsuranceCompany_Code,
		Member_Number:             d.Member_Number,
		Ref_Number:                d.Ref_Number,
		Trx_Number:                d.Trx_Number,
		Appointment_Doctor_Code:   d.Appointment_Doctor_Code,
		Appointment_Doctor:        d.Appointment_Doctor,
		Adm_Employee_Id:           d.Adm_Employee_Id,
		Adm_Employee:              d.Adm_Employee,
		Responsible_Doctor_Code:   d.Responsible_Doctor_Code,
		Responsible_Doctor:        d.Responsible_Doctor,
		Discharge_Method_Code:     d.Discharge_Method_Code,
		RefSource_Name:            d.RefSource_Name,
		Appointment_Id:            d.Appointment_Id,
		Appointment:               d.Appointment,
		EarlyEducation:            d.EarlyEducation,
		MedicalDischargeEducation: d.MedicalDischargeEducation,
		AdmDischargeEducation:     d.AdmDischargeEducation,
		DischargeReason:           d.DischargeReason,
		Status_Code:               d.Status_Code,
		VclaimSep:                 d.VclaimSep,
		StartedAt:                 d.StartedAt,
		FinishedAt:                d.FinishedAt,
		Discharge_Date:            d.Discharge_Date,
		InternalReferences:        d.InternalReferences,
		DeathCause:                d.DeathCause,
		NewStatus:                 d.NewStatus,
		Emergency:                 d.Emergency,
		Inpatient:                 d.Inpatient,
		Rehab:                     d.Rehab,
		RehabChildren:             d.RehabChildren,
		EncounterDocuments:        d.EncounterDocuments,
		Responsible_Nurse_Code:    d.Responsible_Nurse_Code,
		Responsible_Nurse:         d.Responsible_Nurse,
	}
	resp.Main = d.Main
	return resp
}

func ToResponseList(data []Encounter) []ResponseDto {
	resp := make([]ResponseDto, len(data))
	for i, u := range data {
		resp[i] = u.ToResponse()
	}
	return resp
}
