package common

import (
	"fmt"
	"time"

	"github.com/fiskerinc/cloud-services/pkg/common/dbbasemodel"
)

type AddDTCRequest struct {
	Data map[string]DTCReq `validate:"required,gt=0,dive,keys,max=1000,endkeys,dive"`
}
type DTCReq struct {
	EpochUsec int64    `json:"epoch_usec"`
	DTCs      [][]byte `json:"dtcs" validate:"required,gt=0,dive,max=10000,required,gt=0,dive,max=1024"`
}

type DTC_ECU struct {
	ID               int                    `json:"id,omitempty" pg:",pk"`
	VIN              string                 `json:"vin,omitempty" bson:"vin" validate:"vin"`
	ECU              string                 `json:"ecu_name" bson:"ecu" validate:"required,ecu"`
	TroubleCode      int64                  `json:"trouble_code" bson:"dtc"`
	StatusByte       int64                  `json:"status_byte" bson:"status"`
	Epoch_usec       time.Time              `json:"epoch_usec" bson:"timestamp"`
	Created_at       time.Time              `json:"created_at" bson:"created_at"`
	Speed            uint16                 `json:"speed" bson:"speed"`
	Mileage          uint32                 `json:"mileage" bson:"mileage"`
	Voltage          uint16                 `json:"voltage" bson:"voltage"`
	Snapshot         string                 `json:"snapshot,omitempty" bson:"snapshot,omitempty"`
	Information      *DTCInformation        `json:"trouble_code_information,omitempty" pg:"-"`
	StatusByteDecode []DTCStatusByteMeaning `json:"status_byte_meaning,omitempty"  pg:"-"`
	dbbasemodel.DBModelBase
}

type DTC_ECUQuery struct {
	VIN         string `pg:"vin" validate:"vin"`
	ECU         string `pg:"ecu,omit_empty" validate:"required,ecu"`
	TroubleCode int64  `pg:"trouble_code,omit_empty" json:"trouble_code"`
	StartTime   *time.Time
	EndTime     *time.Time
}

type DTCInformation struct {
	ShortName          string `bson:"ShortName"`
	TroubleCode        int64  `bson:"TroubleCode"`
	TroubleCodeHex     string `bson:"TroubleCodeHex"`
	DisplayTroubleCode string `bson:"DisplayTroubleCode"`
	ErrorText          struct {
		Ti   string `bson:"TI"`
		Text string `bson:"Text"`
	} `bson:"ErrorText"`
	SplDataGroups struct {
		SplDataGroup struct {
			SplDataGroupCaption interface{} `bson:"SplDataGroupCaption"`
			SplData             []struct {
				SemanticInformation string `bson:"SemanticInformation"`
				Ti                  string `bson:"TI"`
				Text                string `bson:"Text"`
			} `bson:"SplData"`
		} `bson:"SplDataGroup"`
	} `bson:"SplDataGroups"`
	// ID  string      `bson:"_id"`
	// OID interface{} `bson:"OId"`
}

func (dtc DTC_ECU) DTCStatusByteMeaning() (statuses []DTCStatusByteMeaning) {
	statuses = make([]DTCStatusByteMeaning, 0)
	if 0b10000000&dtc.StatusByte != 0 {
		statuses = append(statuses, Bit0)
	}
	if 0b01000000&dtc.StatusByte != 0 {
		statuses = append(statuses, Bit1)
	}
	if 0b00100000&dtc.StatusByte != 0 {
		statuses = append(statuses, Bit2)
	}
	if 0b00010000&dtc.StatusByte != 0 {
		statuses = append(statuses, Bit3)
	}
	if 0b00001000&dtc.StatusByte != 0 {
		statuses = append(statuses, Bit4)
	}
	if 0b00000100&dtc.StatusByte != 0 {
		statuses = append(statuses, Bit5)
	}
	if 0b00000010&dtc.StatusByte != 0 {
		statuses = append(statuses, Bit6)
	}
	if 0b00000001&dtc.StatusByte != 0 {
		statuses = append(statuses, Bit7)
	}
	return
}

// Bit meaning from here: https://www.ni.com/docs/en-US/bundle/automotive-diagnostic-command-set-toolkit/page/adcs/udsreportdtcbystatusmaskvi.html#:~:text=Status%20is%20the%20DTC%20status.%20Usually%2C%20this%20is%20a%20bit%20field%20with%20the%20following%20meaning
type DTCStatusByteMeaning string

const (
	Bit0 DTCStatusByteMeaning = "testFailed"
	Bit1 DTCStatusByteMeaning = "testFailedThisMonitoringCycle" //monitoring or operation
	Bit2 DTCStatusByteMeaning = "pendingDTC"
	Bit3 DTCStatusByteMeaning = "confirmedDTC"
	Bit4 DTCStatusByteMeaning = "testNotCompletedSinceLastClear"
	Bit5 DTCStatusByteMeaning = "testFailedSinceLastClear"
	Bit6 DTCStatusByteMeaning = "testNotCompletedThisMonitoringCycle" //monitoring or operation
	Bit7 DTCStatusByteMeaning = "warningIndicatorRequested"
)

func (dtc *DTC_ECU) CacheKey() string {
	return fmt.Sprintf("%s:%s:%d", dtc.VIN, dtc.ECU, dtc.TroubleCode)
}
