package types

import (
	"fmt"
	"time"

	"gorm.io/gorm"
)

type BundleData struct {
	Grupo6              string         `json:"grupo6"`
	Po                  int            `json:"po" gorm:"index"`
	Co                  int            `json:"co"`
	Colada              string         `json:"colada"`
	Calidad             string         `json:"calidad"`
	Matnr               string         `json:"matnr"`
	Dibujo              int            `json:"dibujo"`
	Operador            string         `json:"operador"`
	Serie               int            `json:"serie"`
	Nromatricula        string         `gorm:"primaryKey" json:"nromatricula"`
	NroBulto            string         `json:"nro_bulto"`
	EtiquetaDoble       string         `json:"etiqueta_doble"`
	Fecha               int            `json:"fecha"`
	Turno               string         `json:"turno"`
	Observacion1        string         `json:"observacion1"`
	Observacion2        string         `json:"observacion2"`
	Observacion3        string         `json:"observacion3"`
	PaqueteLongitud     float64        `json:"paquete_longitud"`
	PaqueteAncho        int            `json:"paquete_ancho"`
	PaqueteAlto         float64        `json:"paquete_alto"`
	PaquetePeso         int            `json:"paquete_peso"`
	PaqueteNroSecciones int            `json:"paquete_nro_secciones"`
	PaqueteNroMantos    int            `json:"paquete_nro_mantos"`
	PaqueteNroSeccManto int            `json:"paquete_nro_secc_manto"`
	SeccionTipo         string         `gorm:"index" json:"seccion_tipo"`
	SeccionLongitud     int            `json:"seccion_longitud"`
	SeccionAncho        float64        `json:"seccion_ancho"`
	SeccionAlto         float64        `json:"seccion_alto"`
	Idioma              string         `json:"idioma"`
	Destino             int            `json:"destino"`
	Hora                int            `json:"hora"`
	Horario             int            `json:"horario"`
	Inst                string         `json:"inst"`
	Tren                int            `json:"tren"`
	Normed              string         `json:"normed"`
	Norpro              string         `json:"norpro"`
	Nortol              string         `json:"nortol"`
	Spras               string         `json:"spras"`
	Statu               int            `json:"statu"`
	Crlf                string         `json:"crlf"`
	Maquina             int            `json:"maquina"`
	Padre               string         `json:"padre"`
	Paqpadre            string         `json:"paqpadre"`
	RelevantTime        string         `json:"relevant_time"`
	Desvio              float64        `json:"desvio"`
	Pesoteorico         float64        `json:"pesoteorico"`
	PesoteoricoReal     float64        `json:"pesoteorico_real"`
	DesvioTeoricoReal   float64        `json:"desvio_teorico_real"`
	FechaImpresion      string         `json:"fecha_impresion"`
	PesoNivel1          float64        `json:"peso_nivel1"`
	L3Sended            bool           `json:"l3_sended,omitempty"`
	Confirmed           bool           `json:"confirmed,omitempty"`
	SAP                 bool           `json:"sap,omitempty"`
	CreatedAt           time.Time      `gorm:"->;<-:create" json:"createdat,omitempty"`
	UpdatedAt           time.Time      `json:"updatedat,omitempty"`
	DeletedAt           gorm.DeletedAt `gorm:"index" json:"deletedat,omitempty"`
}

func (BundleData) TableName() string {
	return "bundles"
}

func (b *BundleData) BeforeSave(tx *gorm.DB) error {
	// calculate and assign teorical weight
	PesoTeorico(b)
	// calculation of the deviation of the actual weight from the theoretical weight
	if err := Desvio(b); err != nil {
		return err
	}
	// calculation of the "real" theorical weight means lenght + the lenght of the disc saw (10mm)
	PesoTeoricoReal(b)
	if err := DesvioReal(b); err != nil {
		return err
	}
	// // calculation of the deviation between theorical and SAP
	// if err := PesoDesvioSAP(b); err != nil {
	// 	return err
	// }
	return nil
}

func PesoTeorico(b *BundleData) {
	// get the lenght of the bundle
	bl := b.PaqueteLongitud
	// weight per meter
	bw := b.PaqueteAlto
	// number of pieces
	bp := b.PaqueteNroSecciones
	// calculate theoretical weight
	bt := bl * bw * float64(bp)
	// set value
	b.Pesoteorico = bt
}

func Desvio(b *BundleData) error {
	// check if theorical is 0
	if b.Pesoteorico == 0 {
		return fmt.Errorf("theorical weight is zero")
	}
	// calculate deviation
	dv := float64(b.PaquetePeso) - (b.Pesoteorico)
	// % of deviation
	pdv := (dv / float64(b.Pesoteorico)) * 100
	// set value
	b.Desvio = pdv
	// done
	return nil
}

func PesoTeoricoReal(b *BundleData) {
	// get the lenght of the bundle
	bl := b.PaqueteLongitud + 0.01 // added 10 mm
	// weight per meter
	bw := b.PaqueteAlto
	// number of pieces
	bp := b.PaqueteNroSecciones
	// calculate theoretical weight
	bt := bl * bw * float64(bp)
	// set value
	b.PesoteoricoReal = bt
}

func DesvioReal(b *BundleData) error {
	// check if theorical is 0
	if b.PesoteoricoReal == 0 {
		return fmt.Errorf("theorical weight is zero")
	}
	// calculate deviation
	dv := float64(b.PaquetePeso) - (b.PesoteoricoReal)
	// % of deviation
	pdv := (dv / float64(b.PesoteoricoReal)) * 100
	// set value
	b.DesvioTeoricoReal = pdv
	// done
	return nil
}

func PesoDesvioSAP(b *BundleData) error {
	// check if theorical is 0
	if b.Pesoteorico == 0 {
		return fmt.Errorf("theorical weight is zero")
	}
	// check if SAP deviation is 0
	if b.PesoNivel1 == 0 {
		return fmt.Errorf("SAP deviation not found")
	}
	// get deviation
	dvs := b.PesoNivel1
	// calculates weight
	res := b.Pesoteorico + (b.Pesoteorico * (dvs / 100))
	// set weight value
	b.PesoNivel1 = res
	return nil
}
