package handlers_test

import (
	"encoding/base64"
	"fmt"
	"testing"

	"github.com/fiskerinc/cloud-services/services/optimus/handlers"

	"github.com/fiskerinc/cloud-services/pkg/common"
	fm29 "github.com/fiskerinc/cloud-services/pkg/dbc/fm29_frsd0"
	fm390 "github.com/fiskerinc/cloud-services/pkg/dbc/fm29_frsd390"
	dbc "github.com/fiskerinc/cloud-services/pkg/dbc/models"
	"github.com/fiskerinc/cloud-services/pkg/grpc/kafka_grpc"
	rutils "github.com/fiskerinc/cloud-services/pkg/redis/redisutils"

	"github.com/pkg/errors"
	"github.com/stretchr/testify/assert"
)

var produceSignalsCorrectPayload = kafka_grpc.GRPC_BatchPayload{
	Handler: "canbus",
	Data: &kafka_grpc.GRPC_CANData{
		EpochUsec: 1653255445,
		Dropped:   10,
		Filtered:  20,
		Frames: []*kafka_grpc.GRPC_CANFrame{
			{ID: 5, Value: []byte("AAAGAB6cCBY=")},
			{ID: 624, Value: []byte("AAAGAB6cCBY=")},
			{ID: 1290, Value: []byte("CACAAIAAAAA=")},
			{ID: 1287, Value: []byte("ACBAAAoANLI=")},
			{ID: 1311, Value: []byte("afaA9wBkkgA=")},
			{ID: 1317, Value: []byte("MAAwIAAAAAA=")},
			{ID: 1318, Value: []byte("D9M1YAF78aA=")},
			{ID: 5, Value: []byte("AAAGAB6cCBY=")},
		},
	},
	Version: fm29.Hash,
}

var produceInvalidSignalsPayload = kafka_grpc.GRPC_BatchPayload{
	Handler: "canbus",
	Data: &kafka_grpc.GRPC_CANData{
		EpochUsec: 1653255445,
		Dropped:   10,
		Filtered:  20,
		Frames: []*kafka_grpc.GRPC_CANFrame{
			{ID: 1169, Value: []byte("MDAwMDgwMDA=")},
			{ID: 576, Value: []byte("3wBMc0yCAAA=")},
			{ID: 624, Value: []byte("MDAwMDA2MDA=")},
			{ID: 640, Value: []byte("MDAwMDI4RTY=")},
			{ID: 1168, Value: []byte("MDAwMDRFRTg=")},
			{ID: 1169, Value: []byte("MDAwMDgwMDA=")},
			{ID: 576, Value: []byte("3wBMc0yCAAA=")},
			{ID: 624, Value: []byte("MDAwMDA2MDA=")},
			{ID: 640, Value: []byte("MDAwMDI4RTY=")},
			{ID: 1168, Value: []byte("MDAwMDRFRTg=")},
		},
	},
	Version: fm390.Hash,
}

var produceOutOfRangeSignalsPayload = kafka_grpc.GRPC_BatchPayload{
	Handler: "canbus",
	Data: &kafka_grpc.GRPC_CANData{
		EpochUsec: 1653255445,
		Dropped:   10,
		Filtered:  20,
		Frames: []*kafka_grpc.GRPC_CANFrame{
			{ID: 1073741824, Value: []byte("MDAwMDgwMDA=")},
			{ID: 1073756897, Value: []byte("3wBMc0yCAAA=")},
			{ID: 5242880, Value: []byte("MDAwMDA2MDA=")},
			{ID: 308346880, Value: []byte("MDAwMDI4RTY=")},
			{ID: 1188096, Value: []byte("MDAwMDRFRTg=")},
			{ID: -318242816, Value: []byte("MDAwMDgwMDA=")},
			{ID: 1073741824, Value: []byte("MDAwMDgwMDA=")},
			{ID: 1073756897, Value: []byte("3wBMc0yCAAA=")},
			{ID: 5242880, Value: []byte("MDAwMDA2MDA=")},
			{ID: 308346880, Value: []byte("MDAwMDI4RTY=")},
			{ID: 1188096, Value: []byte("MDAwMDRFRTg=")},
			{ID: -318242816, Value: []byte("MDAwMDgwMDA=")},
		},
	},
	Version: fm390.Hash,
}

var produceSignalsAllValidPayload = kafka_grpc.GRPC_BatchPayload{
	Handler: "canbus",
	Data: &kafka_grpc.GRPC_CANData{
		EpochUsec: 1653255445,
		Dropped:   10,
		Filtered:  20,
		Frames: []*kafka_grpc.GRPC_CANFrame{
			{ID: 1290, Value: []byte("CACAAIAAAAA=")},
			{ID: 1287, Value: []byte("ACBAAAoANLI=")},
			{ID: 1317, Value: []byte("MAAwIAAAAAA=")},
			{ID: 1318, Value: []byte("D9M1YAF78aA=")},
		},
	},
	Version: fm29.Hash,
}

var correctExpBatch = []common.CANSignal{
	{VIN: "TESTVIN123", Timestamp: 0, ID: 1290, Name: "VCU_PwrBattHVChkTiOut", Value: 0, Description: ""},
	{VIN: "TESTVIN123", Timestamp: 0, ID: 1290, Name: "VCU_HVSysPrecTiOut", Value: 0, Description: ""},
	{VIN: "TESTVIN123", Timestamp: 0, ID: 1290, Name: "VCU_HVSysChkTiOut", Value: 0, Description: ""},
	{VIN: "TESTVIN123", Timestamp: 0, ID: 1290, Name: "VCU_PwrBattPosBreakStsTiOut", Value: 1, Description: ""},
	{VIN: "TESTVIN123", Timestamp: 0, ID: 1290, Name: "VCU_HVDchaStsTiOut", Value: 0, Description: ""},
	{VIN: "TESTVIN123", Timestamp: 0, ID: 1290, Name: "VCU_PartSaveStsTiOut", Value: 0, Description: ""},
	{VIN: "TESTVIN123", Timestamp: 0, ID: 1290, Name: "VCU_CellVoltLoHVPwrOffFlg", Value: 0, Description: ""},
	{VIN: "TESTVIN123", Timestamp: 0, ID: 1290, Name: "VCU_EEPROMCellVoltLoHVPwrOffFlg", Value: 0, Description: ""},
	{VIN: "TESTVIN123", Timestamp: 0, ID: 1290, Name: "VCU_VehBootLoaderFlg", Value: 0, Description: ""},
	{VIN: "TESTVIN123", Timestamp: 0, ID: 1290, Name: "VCU_FobdHVPwrOnFlg", Value: 0, Description: ""},
	{VIN: "TESTVIN123", Timestamp: 0, ID: 1290, Name: "VCU_HVPwrOffReq", Value: 0, Description: ""},
	{VIN: "TESTVIN123", Timestamp: 0, ID: 1290, Name: "VCU_VehRemSCModPwrOnReq", Value: 0, Description: ""},
	{VIN: "TESTVIN123", Timestamp: 0, ID: 1290, Name: "VCU_VehRemOperModPwrOnReq", Value: 0, Description: ""},
	{VIN: "TESTVIN123", Timestamp: 0, ID: 1290, Name: "VCU_DDmdTq", Value: 0, Description: ""},
	{VIN: "TESTVIN123", Timestamp: 0, ID: 1290, Name: "VCU_TqLim", Value: 0, Description: ""},
	{VIN: "TESTVIN123", Timestamp: 0, ID: 1290, Name: "VCU_MotDampgFobdSts", Value: 0, Description: ""},
	{VIN: "TESTVIN123", Timestamp: 0, ID: 1290, Name: "VCU_EEPROMSts", Value: 0, Description: ""},
	{VIN: "TESTVIN123", Timestamp: 0, ID: 1287, Name: "VCU_OTAVehInhb_QM_Fb", Value: 0, Description: ""},
	{VIN: "TESTVIN123", Timestamp: 0, ID: 1287, Name: "VCU_OTAVehCdnChk_QM_sts", Value: 0, Description: ""},
	{VIN: "TESTVIN123", Timestamp: 0, ID: 1287, Name: "VCU_DrvAvl", Value: 0, Description: ""},
	{VIN: "TESTVIN123", Timestamp: 0, ID: 1287, Name: "VCU_CllsnSigSts", Value: 0, Description: ""},
	{VIN: "TESTVIN123", Timestamp: 0, ID: 1287, Name: "VCU_VehSts_GB", Value: 2, Description: ""},
	{VIN: "TESTVIN123", Timestamp: 0, ID: 1287, Name: "VCU_MCUOverTFlt_GB", Value: 0, Description: ""},
	{VIN: "TESTVIN123", Timestamp: 0, ID: 1287, Name: "VCU_DrvrMotOverTFlt_GB", Value: 0, Description: ""},
	{VIN: "TESTVIN123", Timestamp: 0, ID: 1287, Name: "VCU_SOCTooLoAlrm", Value: 0, Description: ""},
	{VIN: "TESTVIN123", Timestamp: 0, ID: 1287, Name: "VCU_SOCJumpAlrm", Value: 0, Description: ""},
	{VIN: "TESTVIN123", Timestamp: 0, ID: 1287, Name: "VCU_PwrBattPackMismatAlrm", Value: 0, Description: ""},
	{VIN: "TESTVIN123", Timestamp: 0, ID: 1287, Name: "VCU_SOCTooHiAlrm", Value: 0, Description: ""},
	{VIN: "TESTVIN123", Timestamp: 0, ID: 1287, Name: "VCU_DCDCEnaCmd", Value: 0, Description: ""},
	{VIN: "TESTVIN123", Timestamp: 0, ID: 1287, Name: "VCU_PwrBattECCEnaCmd", Value: 1, Description: ""},
	{VIN: "TESTVIN123", Timestamp: 0, ID: 1287, Name: "VCU_MstRlyCtrlCmd", Value: 0, Description: ""},
	{VIN: "TESTVIN123", Timestamp: 0, ID: 1287, Name: "VCU_DCDCOutpVoltCmd", Value: 0, Description: ""},
	{VIN: "TESTVIN123", Timestamp: 0, ID: 1287, Name: "VCU_CCCnctnVolt", Value: 1, Description: ""},
	{VIN: "TESTVIN123", Timestamp: 0, ID: 1287, Name: "VCU_GearSig_GB", Value: 0, Description: ""},
	{VIN: "TESTVIN123", Timestamp: 0, ID: 1287, Name: "VCU_DrvrMotNr_GB", Value: 0, Description: ""},
	{VIN: "TESTVIN123", Timestamp: 0, ID: 1287, Name: "VCU_BattVolt", Value: 13.49, Description: ""},
	{VIN: "TESTVIN123", Timestamp: 0, ID: 1317, Name: "TBOX_525_CheckSum", Value: 48, Description: ""},
	{VIN: "TESTVIN123", Timestamp: 0, ID: 1317, Name: "TBOX_525_AliveCounter", Value: 0, Description: ""},
	{VIN: "TESTVIN123", Timestamp: 0, ID: 1317, Name: "TBOX_GPSHei", Value: -115, Description: ""},
	{VIN: "TESTVIN123", Timestamp: 0, ID: 1318, Name: "TBOX_GPSLongi", Value: 85.5, Description: ""},
	{VIN: "TESTVIN123", Timestamp: 0, ID: 1318, Name: "TBOX_GPSLati", Value: -65.1, Description: ""},
}

func TestProduceSignalsFromMessageBatch(t *testing.T) {
	invalidVersionPayload := produceSignalsCorrectPayload
	invalidVersionPayload.Version = "12"

	tests := map[string]struct {
		payload      *kafka_grpc.GRPC_BatchPayload
		cacheSetMock rutils.CacheSetMock
		batchError   error
		expBatch     []common.CANSignal
		expError     error
	}{
		"correct": {
			payload:  &produceSignalsCorrectPayload,
			expBatch: correctExpBatch,
		},
		"all valid": {
			payload:  &produceSignalsAllValidPayload,
			expBatch: correctExpBatch,
		},
		"invalid_payload": {
			payload:  nil,
			expError: errors.WithStack(errors.New("payload is nil")),
		},
		"invalid_version": {
			payload:  &invalidVersionPayload,
			expError: errors.New("DBC 12 does not exists"),
		},
		"invalid_signals": {
			payload: &produceInvalidSignalsPayload,
		},
		"out_of_range_signals": {
			payload: &produceOutOfRangeSignalsPayload,
		},
	}

	for name, tt := range tests {
		t.Run(name, func(t *testing.T) {
			dbc.SetInvalidCANIDCache(dbc.NewInvalidCANIDCache())
			batch, err := handlers.ProduceSignalsFromMessageBatch("TESTVIN123", tt.payload)
			if err != nil && tt.expError != nil {
				assert.Equal(t, tt.expError.Error(), err.Error())
				return
			}

			assert.Equal(t, tt.expError, err)
			assert.Equal(t, tt.expBatch, batch)
		})
	}
}

func TestGenB64(t *testing.T) {
	t.Skip()

	// example of generating binary CAN signal data

	msg := fm29.NewESP_0x114()
	msg.SetESP_ActvSig_DTC(true)

	data := msg.Frame().Data
	b64 := base64.StdEncoding.EncodeToString([]byte(data[:]))
	fmt.Println(msg.Descriptor().ID)
	fmt.Println(b64)

	t.Error("done")
}
