package handlers_test

import (
	"errors"
	"fmt"
	"net/http"
	"strings"
	"testing"
	"time"

	"github.com/fiskerinc/cloud-services/services/attendant/controllers"
	"github.com/fiskerinc/cloud-services/services/attendant/services"

	"github.com/fiskerinc/cloud-services/pkg/common"
	"github.com/fiskerinc/cloud-services/pkg/common/manifestfingerprintparams"
	"github.com/fiskerinc/cloud-services/pkg/db/queries/mocks"
	"github.com/fiskerinc/cloud-services/pkg/redis/tester"
	th "github.com/fiskerinc/cloud-services/pkg/testhelper"
	"github.com/fiskerinc/cloud-services/pkg/utils/elptr"
	vconfig "github.com/fiskerinc/cloud-services/pkg/vehicleconfig"
)

var (
	schemaToTRex = "file://" + th.GetSchemaDirPath() + "/trex/RXMessage.json"
	schemaToHMI  = "file://" + th.GetSchemaDirPath() + "/hmi/RXMessage.json"
)

func TestCarUpdateProgress(t *testing.T) {
	testGetSetResult := `["valid-cognito-id-1","valid-cognito-id-2"]`
	testVIN := "JH4KA7680RC01"
	mobile1Key := "3:valid-cognito-id-1"
	mobile2Key := "3:valid-cognito-id-2"
	hmiKey := "2:JH4KA7680RC01"
	trexKey := common.TRex.Key(testVIN)
	carupdateKey := "carupdate:297"
	var bhex common.BinaryHex
	expectedExpire := 3600
	bhex = []byte("test")

	fingerprintTime, _ := time.Parse("02/01/06", "19/01/24")
	fpp := manifestfingerprintparams.MockFingerprintParamer{
		ManifestSerialValue: "00000000000000000",
		Time:                fingerprintTime,
	}
	manifestfingerprintparams.SetFPParams(&fpp)

	manifest := common.UpdateManifest{
		ID:              1,
		Name:            "test",
		Version:         "MANIFEST_VERSION",
		SUMS:            "2023.10.01.00.E",
		Description:     "description",
		ReleaseNotes:    "http://releasenotes.com",
		Country:         "US",
		PowerTrain:      "MD23",
		Restraint:       "None",
		Model:           "Ocean",
		Trim:            "Sport",
		Year:            2022,
		BodyType:        "truck",
		RollbackEnabled: true,
		Type:            "standard",
		ECUs: []*common.UpdateManifestECU{
			{
				ECU:          "ICC",
				Version:      "version",
				HWVersions:   []string{"hardware_version"},
				Mode:         "D",
				SelfDownload: true,
				Files: []*common.UpdateManifestFile{
					{
						FileID:        "fileid",
						URL:           "http://download.com",
						Filename:      "filename.bin",
						FileSize:      10000,
						FileType:      common.Software,
						WriteRegionID: 2222,
						WriteRegion: common.MemoryRegion{
							ID:     2000,
							Offset: 10000,
							Length: 20,
						},
						DBModelBase: th.Timestamp,
					},
				},
				DBModelBase: th.Timestamp,
			},
			{
				ECU:             "ADAS",
				Version:         "version",
				HWVersions:      []string{"hardware_version"},
				Mode:            "A",
				InstallPriority: 10,
				Files: []*common.UpdateManifestFile{
					{
						FileID:        "fileid",
						URL:           "http://download.com",
						Filename:      "adas.bin",
						FileSize:      9999,
						FileType:      common.Software,
						WriteRegionID: 9999,
						WriteRegion: common.MemoryRegion{
							ID:     8888,
							Offset: 8888,
							Length: 8888,
						},
						DBModelBase: th.Timestamp,
					},
				},
				ECCKeys: &common.ECCKeys{
					ECU:      "ADAS",
					PrivKey1: &bhex,
					PrivKey2: &bhex,
					PrivKey3: &bhex,
					PubKey1:  &bhex,
					PubKey2:  &bhex,
					PubKey3:  &bhex,
				},
				DBModelBase: th.Timestamp,
			},
			{
				ECU:             "ECUA",
				Version:         "version",
				HWVersions:      []string{"hardware_version"},
				Mode:            "A",
				InstallPriority: 5,
				Files: []*common.UpdateManifestFile{
					{
						FileID:        "fileid",
						URL:           "http://download.com",
						Filename:      "adas.bin",
						FileSize:      9999,
						FileType:      common.Software,
						WriteRegionID: 9999,
						WriteRegion: common.MemoryRegion{
							ID:     8888,
							Offset: 8888,
							Length: 8888,
						},
						DBModelBase: th.Timestamp,
					},
					{
						FileID:        "SHOULD_NOT_BE_IN_UPDATE",
						URL:           "http://download.com/SHOULD_NOT_BE_IN_UPDATE.bin",
						FileSize:      1000,
						Checksum:      "AAAAAAA",
						FileType:      common.Calibration,
						EraseRegionID: 200,
						EraseRegion: &common.MemoryRegion{
							Offset: 201,
							Length: 202,
						},
						Parsed:        elptr.ElPtr(false),
						WriteRegionID: 100,
						WriteRegion: common.MemoryRegion{
							Offset: 101,
							Length: 102,
						},
						DBModelBase: th.Timestamp,
					},
					{
						FileID:        "MUST_BE_IN_UPDATE",
						URL:           "http://download.com/MUST_BE_IN_UPDATE.bin",
						FileSize:      1000,
						Checksum:      "AAAAAAA",
						FileType:      common.Calibration,
						EraseRegionID: 200,
						EraseRegion: &common.MemoryRegion{
							Offset: 201,
							Length: 202,
						},
						Parsed:        elptr.ElPtr(true),
						WriteRegionID: 100,
						WriteRegion: common.MemoryRegion{
							Offset: 101,
							Length: 102,
						},
						DBModelBase: th.Timestamp,
					},
				},
				ECCKeys: &common.ECCKeys{
					ECU:      "ECUA",
					PrivKey1: &bhex,
					PrivKey2: &bhex,
					PrivKey3: &bhex,
					PubKey1:  &bhex,
					PubKey2:  &bhex,
					PubKey3:  &bhex,
				},
				DBModelBase: th.Timestamp,
			},
		},
		DBModelBase: th.Timestamp,
	}
	ecuaRollback := []*common.UpdateManifestECU{
		{
			ID:               100,
			UpdateManifestID: 200,
			ECU:              "ECUA",
			Version:          "VERSIONOLD",
			HWVersions:       []string{"hardware_version"},
			Mode:             "A",
			DBModelBase:      th.Timestamp,
			Files: []*common.UpdateManifestFile{
				{
					FileID:              "FILEIDOLD",
					UpdateManifestECUID: 1001,
					Filename:            "FILENAMEOLD",
					URL:                 "URLOLD",
					FileType:            common.Software,
					WriteRegionID:       700,
					WriteRegion: common.MemoryRegion{
						Offset: 701,
						Length: 702,
					},
					FileSize:    240,
					DBModelBase: th.Timestamp,
				},
			},
			ECCKeys: &common.ECCKeys{
				ECU:      "ECUA",
				PrivKey1: &bhex,
				PrivKey2: &bhex,
				PrivKey3: &bhex,
				PubKey1:  &bhex,
				PubKey2:  &bhex,
				PubKey3:  &bhex,
			},
		},
	}
	mockDB := &services.DB{}
	mockCars := &mocks.MockCars{}
	mockCarUpdates := &mocks.MockCarUpdates{
		SelectCarUpdateResponse: &common.CarUpdate{
			UpdateManifestID: 816,
			UpdateManifest: &common.UpdateManifest{
				ID: 816,
			},
		},
	}
	mockManifests := &mocks.MockUpdateManifests{
		ECUUpdatesMock: func(man *common.UpdateManifestECU, vin string) ([]*common.UpdateManifestECU, error) {
			if man.ECU == "ECUA" {
				return ecuaRollback, nil
			}

			return nil, nil
		},
	}
	mockKeys := &mocks.MockEccKeys{
		MockListResponse: []common.ECCKeys{
			{
				ECU:      "PDU",
				PrivKey1: &bhex,
				PrivKey2: &bhex,
				PrivKey3: &bhex,
				PubKey1:  &bhex,
				PubKey2:  &bhex,
				PubKey3:  &bhex,
			},
			{
				ECU:      "TBOX",
				PrivKey1: &bhex,
				PrivKey2: &bhex,
				PrivKey3: &bhex,
				PubKey1:  &bhex,
				PubKey2:  &bhex,
				PubKey3:  &bhex,
			},
		},
	}
	mockDB.SetCars(mockCars)
	mockDB.SetCarUpdates(mockCarUpdates)
	mockDB.SetECCKeys(mockKeys)
	mockDB.SetManifests(mockManifests)

	mockFoa := FoaServiceMock{}
	services.SetFoaService(&mockFoa)

	mockRedis := tester.NewRedisMock()
	mockKeepAwake := services.NewKeepAwakeService()
	services.SetRedisClientPool(tester.NewMockClientPool(mockRedis))
	mockSap := vconfig.SAPServiceMock{GetConfigurationMock: func(vin string) (common.SAPResponse, error) {
		return common.SAPResponse{
			ModelYear:              2023,
			ModelType:              "Ocean",
			VersionDuringModelYear: "1",
			Features: []common.SAPFeature{
				{
					FamilyCode:  "FamilyCode1",
					FeatureCode: "FeatureCode1",
				},
				{
					FamilyCode:  "FamilyCode2",
					FeatureCode: "FeatureCode2",
				},
			},
		}, nil
	}}
	mockConf := vconfig.ConfigMock{GetVODCDSCodingDataMock: func(request common.VODCDSRequest) (map[string]string, error) {
		return map[string]string{
			"ECUA": "config",
			"VOD":  "00a62299027600000101012200010100010001010101000000000000000000fffeffff000101010101010101010100010001010101000101010100000000000000000000000000010101000100000100010101000201010101000101020101000101010200010101010101010101000101010100010001010101010101010201010000000000000100000101ff00000001010200000000000003ffffffff0000000201010200000100000000000000000000000000000000000000000000000000000000000000000001202310010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}, nil
	}}

	services.SetSapService(mockSap)
	services.SetVehicleConfig(mockConf)
	schemaTesterHMI := th.NewSchemaTestHelper(t, schemaToHMI)
	schemaTesterTRex := th.NewSchemaTestHelper(t, schemaToTRex)

	tests := []AttendentRouteTestCase{
		{
			Name: "[HMI] install_error",
			RedisTestCase: tester.RedisTestCase{
				Device:      common.HMI,
				DeviceKey:   testVIN,
				PayloadData: `{"car_update_id":297,"ecu":"TEST","installed":5,"total_files":10,"msg":"install_error","err":0}`,
				ExpectedCaches: map[string]tester.ExpiringCacheResult{
					carupdateKey: {
						Value:   `{"current_size":0,"ecu":"TEST","errorcode":0,"file_size":0,"file_total":0,"id":297,"installed":5,"status":"install_failed","total_files":10,"total_size":0}`,
						Expires: expectedExpire,
					},
				},
				ExpectedMessages: map[string]string{
					mobile1Key: `{"handler":"car_update_status","data":{"vin":"JH4KA7680RC01","file_current":0,"file_total":0,"package_current":0,"package_total":0,"installed":5,"total_files":10,"car_update_id":297,"ecu":"TEST","msg":"install_failed","err":0}}`,
					mobile2Key: `{"handler":"car_update_status","data":{"vin":"JH4KA7680RC01","file_current":0,"file_total":0,"package_current":0,"package_total":0,"installed":5,"total_files":10,"car_update_id":297,"ecu":"TEST","msg":"install_failed","err":0}}`,
					hmiKey:     `{"handler":"car_update_status","data":{"file_current":0,"file_total":0,"package_current":0,"package_total":0,"installed":5,"total_files":10,"car_update_id":297,"ecu":"TEST","msg":"install_failed","err":0}}`,
				},
				MockRedisGetSet: testGetSetResult,
			},
		},
		{
			Name: "[HMI] download_completed",
			RedisTestCase: tester.RedisTestCase{
				Device:      common.HMI,
				DeviceKey:   testVIN,
				PayloadData: `{"car_update_id":297,"ecu":"ICC","file_current":null,"file_total":null,"package_current":920639485,"package_total":920639485,"installed":null,"total_files":null,"msg":"download_completed","err":null}`,
				ExpectedCaches: map[string]tester.ExpiringCacheResult{
					carupdateKey: {
						Value:   `{"current_size":920639485,"ecu":"ICC","errorcode":0,"file_size":0,"file_total":0,"id":297,"installed":0,"status":"package_download_complete","total_files":0,"total_size":920639485}`,
						Expires: expectedExpire,
					},
				},
				ExpectedMessages: map[string]string{
					trexKey:    `{"handler":"update_manifest","data":{"ecu_updates":[{"name":"ICC","version":"version","hw_version":"hardware_version","self_download":true},{"name":"ECUA","version":"version","hw_version":"hardware_version","configuration":"config","files":[{"file_id":"fileid","url":"http://download.com","file_size":9999,"type":"software","write_region":{"offset":8888,"length":8888}},{"file_id":"MUST_BE_IN_UPDATE","url":"http://download.com/MUST_BE_IN_UPDATE.bin","file_size":1000,"checksum":"AAAAAAA","type":"calibration","write_region":{"offset":101,"length":102},"erase_region":{"offset":201,"length":202}}],"rollback":[{"version":"VERSIONOLD","files":[{"file_id":"FILEIDOLD","url":"URLOLD","file_size":240,"type":"software","write_region":{"offset":701,"length":702}}]}],"ecc_keys":{"level_1":"74657374","level_2":"74657374","level_3":"74657374"}},{"name":"ADAS","version":"version","hw_version":"hardware_version","files":[{"file_id":"fileid","url":"http://download.com","file_size":9999,"type":"software","write_region":{"offset":8888,"length":8888}}],"ecc_keys":{"level_1":"74657374","level_2":"74657374","level_3":"74657374"}}],"fingerprint":"240119FISKER00000000000000000","car_update_id":297,"rollback":true,"type":"standard","vod":"01012299027600000101012200010100010001010101000000000000000000fffeffff000101010101010101010100010001010101000101010100000000000000000000000000010101000100000100010101000201010101000101020101000101010200010101010101010101000101010100010001010101010101010201010000000000000100000101ff00000001010200000000000003ffffffff00000002010102000001000000000000000000000000000000000000000000000000000000000000000000012023100100010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000021","update_duration":30}}`,
					hmiKey:     `{"handler":"car_update_status","data":{"file_current":0,"file_total":0,"package_current":920639485,"package_total":920639485,"installed":0,"total_files":0,"car_update_id":297,"ecu":"ICC","msg":"package_download_complete","err":0}}`,
					mobile1Key: `{"handler":"car_update_status","data":{"vin":"JH4KA7680RC01","file_current":0,"file_total":0,"package_current":920639485,"package_total":920639485,"installed":0,"total_files":0,"car_update_id":297,"ecu":"ICC","msg":"package_download_complete","err":0}}`,
					mobile2Key: `{"handler":"car_update_status","data":{"vin":"JH4KA7680RC01","file_current":0,"file_total":0,"package_current":920639485,"package_total":920639485,"installed":0,"total_files":0,"car_update_id":297,"ecu":"ICC","msg":"package_download_complete","err":0}}`,
				},
				MockRedisGetSet: testGetSetResult,
			},
			MockLoadManifest: &manifest,
		},
		{
			Name: "[HMI] manifest_succeeded",
			RedisTestCase: tester.RedisTestCase{
				Device:      common.HMI,
				DeviceKey:   testVIN,
				PayloadData: `{"car_update_id":297,"ecu":"ICC","file_current":null,"file_total":null,"package_current":920639485,"package_total":920639485,"installed":null,"total_files":null,"msg":"manifest_succeeded","err":null}`,
				ExpectedCaches: map[string]tester.ExpiringCacheResult{
					carupdateKey: {
						Value:   `{"current_size":920639485,"ecu":"ICC","errorcode":0,"file_size":0,"file_total":0,"id":297,"installed":0,"status":"manifest_succeeded","total_files":0,"total_size":920639485}`,
						Expires: expectedExpire,
					},
				},
				ExpectedMessages: map[string]string{
					hmiKey:            `{"handler":"car_update_status","data":{"file_current":0,"file_total":0,"package_current":920639485,"package_total":920639485,"installed":0,"total_files":0,"car_update_id":297,"ecu":"ICC","msg":"manifest_succeeded","err":0}}`,
					mobile1Key:        `{"handler":"car_update_status","data":{"vin":"JH4KA7680RC01","file_current":0,"file_total":0,"package_current":920639485,"package_total":920639485,"installed":0,"total_files":0,"car_update_id":297,"ecu":"ICC","msg":"manifest_succeeded","err":0}}`,
					mobile2Key:        `{"handler":"car_update_status","data":{"vin":"JH4KA7680RC01","file_current":0,"file_total":0,"package_current":920639485,"package_total":920639485,"installed":0,"total_files":0,"car_update_id":297,"ecu":"ICC","msg":"manifest_succeeded","err":0}}`,
					"1:JH4KA7680RC01": `{"handler":"read_ecu_versions","data":{"ecu_name":"*"}}`,
				},
				MockRedisGetSet: testGetSetResult,
			},
			SelectCarUpdate: &common.CarUpdate{
				UpdateManifest: &validUpdateManifest,
			},
		},
		{
			Name: "[TREX] manifest_received",
			RedisTestCase: tester.RedisTestCase{
				Device:      common.TRex,
				DeviceKey:   testVIN,
				PayloadData: `{"car_update_id":297,"msg":"manifest_received","err":-6,"extra_info":""}`,
				ExpectedMessages: map[string]string{
					mobile1Key: `{"handler":"car_update_status","data":{"vin":"JH4KA7680RC01","file_current":0,"file_total":0,"package_current":0,"package_total":0,"installed":0,"total_files":0,"car_update_id":297,"ecu":"","msg":"manifest_received","err":-6}}`,
					mobile2Key: `{"handler":"car_update_status","data":{"vin":"JH4KA7680RC01","file_current":0,"file_total":0,"package_current":0,"package_total":0,"installed":0,"total_files":0,"car_update_id":297,"ecu":"","msg":"manifest_received","err":-6}}`,
					hmiKey:     `{"handler":"car_update_status","data":{"file_current":0,"file_total":0,"package_current":0,"package_total":0,"installed":0,"total_files":0,"car_update_id":297,"ecu":"","msg":"manifest_received","err":-6}}`,
				},
				ExpectedCaches: map[string]tester.ExpiringCacheResult{
					carupdateKey: {
						Value:   `{"current_size":0,"ecu":"","errorcode":-6,"file_size":0,"file_total":0,"id":297,"installed":0,"status":"manifest_received","total_files":0,"total_size":0}`,
						Expires: expectedExpire,
					},
				},
				MockRedisGetSet: testGetSetResult,
			},
		},
		{
			Name: "[TREX] manifest_accepted",
			RedisTestCase: tester.RedisTestCase{
				Device:      common.TRex,
				DeviceKey:   testVIN,
				PayloadData: `{"car_update_id":297,"msg":"manifest_accepted","err":-7,"extra_info":""}`,
				ExpectedCaches: map[string]tester.ExpiringCacheResult{
					carupdateKey: {
						Value:   `{"current_size":0,"ecu":"","errorcode":-7,"file_size":0,"file_total":0,"id":297,"installed":0,"status":"manifest_accepted","total_files":0,"total_size":0}`,
						Expires: expectedExpire,
					},
				},
				ExpectedMessages: map[string]string{
					mobile1Key: `{"handler":"car_update_status","data":{"vin":"JH4KA7680RC01","file_current":0,"file_total":0,"package_current":0,"package_total":0,"installed":0,"total_files":0,"car_update_id":297,"ecu":"","msg":"manifest_accepted","err":-7}}`,
					mobile2Key: `{"handler":"car_update_status","data":{"vin":"JH4KA7680RC01","file_current":0,"file_total":0,"package_current":0,"package_total":0,"installed":0,"total_files":0,"car_update_id":297,"ecu":"","msg":"manifest_accepted","err":-7}}`,
					hmiKey:     `{"handler":"car_update_status","data":{"file_current":0,"file_total":0,"package_current":0,"package_total":0,"installed":0,"total_files":0,"car_update_id":297,"ecu":"","msg":"manifest_accepted","err":-7}}`,
				},
				MockRedisGetSet: testGetSetResult,
			},
		},
		{
			Name: "[TREX] download_started",
			RedisTestCase: tester.RedisTestCase{
				Device:      common.TRex,
				DeviceKey:   testVIN,
				PayloadData: `{"car_update_id":297,"msg":"download_started","err":-14,"extra_info":""}`,
				ExpectedCaches: map[string]tester.ExpiringCacheResult{
					carupdateKey: {
						Value:   `{"current_size":0,"ecu":"","errorcode":-14,"file_size":0,"file_total":0,"id":297,"installed":0,"status":"downloading","total_files":0,"total_size":0}`,
						Expires: expectedExpire,
					},
				},
				ExpectedMessages: map[string]string{
					mobile1Key: `{"handler":"car_update_status","data":{"vin":"JH4KA7680RC01","file_current":0,"file_total":0,"package_current":0,"package_total":0,"installed":0,"total_files":0,"car_update_id":297,"ecu":"","msg":"downloading","err":-14}}`,
					mobile2Key: `{"handler":"car_update_status","data":{"vin":"JH4KA7680RC01","file_current":0,"file_total":0,"package_current":0,"package_total":0,"installed":0,"total_files":0,"car_update_id":297,"ecu":"","msg":"downloading","err":-14}}`,
					hmiKey:     `{"handler":"car_update_status","data":{"file_current":0,"file_total":0,"package_current":0,"package_total":0,"installed":0,"total_files":0,"car_update_id":297,"ecu":"","msg":"downloading","err":-14}}`,
				},
				MockRedisGetSet: testGetSetResult,
			},
		},
		{
			Name: "[TREX] downloading",
			RedisTestCase: tester.RedisTestCase{
				Device:      common.TRex,
				DeviceKey:   testVIN,
				PayloadData: `{"car_update_id":297,"ecu":"ADAS","file_current":1048576,"file_total":1264672,"package_current":1048576,"package_total":2529856,"msg":"downloading","err":0}`,
				ExpectedCaches: map[string]tester.ExpiringCacheResult{
					carupdateKey: {
						Value:   `{"current_size":1048576,"ecu":"ADAS","errorcode":0,"file_size":1048576,"file_total":1264672,"id":297,"installed":0,"status":"downloading","total_files":0,"total_size":2529856}`,
						Expires: expectedExpire,
					},
				},
				ExpectedMessages: map[string]string{
					mobile1Key: `{"handler":"car_update_status","data":{"vin":"JH4KA7680RC01","file_current":1048576,"file_total":1264672,"package_current":1048576,"package_total":2529856,"installed":0,"total_files":0,"car_update_id":297,"ecu":"ADAS","msg":"downloading","err":0}}`,
					mobile2Key: `{"handler":"car_update_status","data":{"vin":"JH4KA7680RC01","file_current":1048576,"file_total":1264672,"package_current":1048576,"package_total":2529856,"installed":0,"total_files":0,"car_update_id":297,"ecu":"ADAS","msg":"downloading","err":0}}`,
					hmiKey:     `{"handler":"car_update_status","data":{"file_current":1048576,"file_total":1264672,"package_current":1048576,"package_total":2529856,"installed":0,"total_files":0,"car_update_id":297,"ecu":"ADAS","msg":"downloading","err":0}}`,
				},
				MockRedisGetSet: testGetSetResult,
			},
		},
		{
			Name: "[TREX] download_completed ECU 1",
			RedisTestCase: tester.RedisTestCase{
				Device:      common.TRex,
				DeviceKey:   testVIN,
				PayloadData: `{"car_update_id":297,"ecu":"ADAS","file_current":1264672,"file_total":1264672,"package_current":1264672,"package_total":2529856,"msg":"download_completed","err":0}`,
				ExpectedCaches: map[string]tester.ExpiringCacheResult{
					carupdateKey: {
						Value:   `{"current_size":1264672,"ecu":"ADAS","errorcode":0,"file_size":1264672,"file_total":1264672,"id":297,"installed":0,"status":"downloading","total_files":0,"total_size":2529856}`,
						Expires: expectedExpire,
					},
				},
				ExpectedMessages: map[string]string{
					mobile1Key: `{"handler":"car_update_status","data":{"vin":"JH4KA7680RC01","file_current":1264672,"file_total":1264672,"package_current":1264672,"package_total":2529856,"installed":0,"total_files":0,"car_update_id":297,"ecu":"ADAS","msg":"downloading","err":0}}`,
					mobile2Key: `{"handler":"car_update_status","data":{"vin":"JH4KA7680RC01","file_current":1264672,"file_total":1264672,"package_current":1264672,"package_total":2529856,"installed":0,"total_files":0,"car_update_id":297,"ecu":"ADAS","msg":"downloading","err":0}}`,
					hmiKey:     `{"handler":"car_update_status","data":{"file_current":1264672,"file_total":1264672,"package_current":1264672,"package_total":2529856,"installed":0,"total_files":0,"car_update_id":297,"ecu":"ADAS","msg":"downloading","err":0}}`,
				},
				MockRedisGetSet: testGetSetResult,
			},
		},
		{
			Name: "[TREX] download_started ECU 2",
			RedisTestCase: tester.RedisTestCase{
				Device:      common.TRex,
				DeviceKey:   testVIN,
				PayloadData: `{"car_update_id":297,"ecu":"EKS","file_current":0,"file_total":1265184,"package_current":1264672,"package_total":2529856,"msg":"download_started","err":0}`,
				ExpectedCaches: map[string]tester.ExpiringCacheResult{
					carupdateKey: {
						Value:   `{"current_size":1264672,"ecu":"EKS","errorcode":0,"file_size":0,"file_total":1265184,"id":297,"installed":0,"status":"downloading","total_files":0,"total_size":2529856}`,
						Expires: expectedExpire,
					},
				},
				ExpectedMessages: map[string]string{
					mobile1Key: `{"handler":"car_update_status","data":{"vin":"JH4KA7680RC01","file_current":0,"file_total":1265184,"package_current":1264672,"package_total":2529856,"installed":0,"total_files":0,"car_update_id":297,"ecu":"EKS","msg":"downloading","err":0}}`,
					mobile2Key: `{"handler":"car_update_status","data":{"vin":"JH4KA7680RC01","file_current":0,"file_total":1265184,"package_current":1264672,"package_total":2529856,"installed":0,"total_files":0,"car_update_id":297,"ecu":"EKS","msg":"downloading","err":0}}`,
					hmiKey:     `{"handler":"car_update_status","data":{"file_current":0,"file_total":1265184,"package_current":1264672,"package_total":2529856,"installed":0,"total_files":0,"car_update_id":297,"ecu":"EKS","msg":"downloading","err":0}}`,
				},
				MockRedisGetSet: testGetSetResult,
			},
		},
		{
			Name: "[TREX] downloading ECU 2",
			RedisTestCase: tester.RedisTestCase{
				Device:      common.TRex,
				DeviceKey:   testVIN,
				PayloadData: `{"car_update_id":297,"ecu":"EKS","file_current":1048576,"file_total":1265184,"package_current":2313248,"package_total":2529856,"msg":"downloading","err":0}`,
				ExpectedCaches: map[string]tester.ExpiringCacheResult{
					carupdateKey: {
						Value:   `{"current_size":2313248,"ecu":"EKS","errorcode":0,"file_size":1048576,"file_total":1265184,"id":297,"installed":0,"status":"downloading","total_files":0,"total_size":2529856}`,
						Expires: expectedExpire,
					},
				},
				ExpectedMessages: map[string]string{
					mobile1Key: `{"handler":"car_update_status","data":{"vin":"JH4KA7680RC01","file_current":1048576,"file_total":1265184,"package_current":2313248,"package_total":2529856,"installed":0,"total_files":0,"car_update_id":297,"ecu":"EKS","msg":"downloading","err":0}}`,
					mobile2Key: `{"handler":"car_update_status","data":{"vin":"JH4KA7680RC01","file_current":1048576,"file_total":1265184,"package_current":2313248,"package_total":2529856,"installed":0,"total_files":0,"car_update_id":297,"ecu":"EKS","msg":"downloading","err":0}}`,
					hmiKey:     `{"handler":"car_update_status","data":{"file_current":1048576,"file_total":1265184,"package_current":2313248,"package_total":2529856,"installed":0,"total_files":0,"car_update_id":297,"ecu":"EKS","msg":"downloading","err":0}}`,
				},
				MockRedisGetSet: testGetSetResult,
			},
		},
		{
			Name: "[TREX] download_completed ECU 2",
			RedisTestCase: tester.RedisTestCase{
				Device:      common.TRex,
				DeviceKey:   testVIN,
				PayloadData: `{"car_update_id":297,"ecu":"EKS","file_current":1265184,"file_total":1265184,"package_current":2529856,"package_total":2529856,"msg":"download_completed","err":0}`,
				ExpectedCaches: map[string]tester.ExpiringCacheResult{
					carupdateKey: {
						Value:   `{"current_size":2529856,"ecu":"EKS","errorcode":0,"file_size":1265184,"file_total":1265184,"id":297,"installed":0,"status":"package_download_complete","total_files":0,"total_size":2529856}`,
						Expires: expectedExpire,
					},
				},
				ExpectedMessages: map[string]string{
					mobile1Key: `{"handler":"car_update_status","data":{"vin":"JH4KA7680RC01","file_current":1265184,"file_total":1265184,"package_current":2529856,"package_total":2529856,"installed":0,"total_files":0,"car_update_id":297,"ecu":"EKS","msg":"package_download_complete","err":0}}`,
					mobile2Key: `{"handler":"car_update_status","data":{"vin":"JH4KA7680RC01","file_current":1265184,"file_total":1265184,"package_current":2529856,"package_total":2529856,"installed":0,"total_files":0,"car_update_id":297,"ecu":"EKS","msg":"package_download_complete","err":0}}`,
					hmiKey:     `{"handler":"car_update_status","data":{"file_current":1265184,"file_total":1265184,"package_current":2529856,"package_total":2529856,"installed":0,"total_files":0,"car_update_id":297,"ecu":"EKS","msg":"package_download_complete","err":0}}`,
				},
				MockRedisGetSet: testGetSetResult,
			},
		},
		{
			Name: "[TREX] package_download_complete",
			RedisTestCase: tester.RedisTestCase{
				Device:      common.TRex,
				DeviceKey:   testVIN,
				PayloadData: `{"car_update_id":297,"msg":"download_completed","err":-15,"extra_info":""}`,
				ExpectedCaches: map[string]tester.ExpiringCacheResult{
					carupdateKey: {
						Value:   `{"current_size":0,"ecu":"","errorcode":-15,"file_size":0,"file_total":0,"id":297,"installed":0,"status":"package_download_complete","total_files":0,"total_size":0}`,
						Expires: expectedExpire,
					},
				},
				ExpectedMessages: map[string]string{
					mobile1Key: `{"handler":"car_update_status","data":{"vin":"JH4KA7680RC01","file_current":0,"file_total":0,"package_current":0,"package_total":0,"installed":0,"total_files":0,"car_update_id":297,"ecu":"","msg":"package_download_complete","err":-15}}`,
					mobile2Key: `{"handler":"car_update_status","data":{"vin":"JH4KA7680RC01","file_current":0,"file_total":0,"package_current":0,"package_total":0,"installed":0,"total_files":0,"car_update_id":297,"ecu":"","msg":"package_download_complete","err":-15}}`,
					hmiKey:     `{"handler":"car_update_status","data":{"file_current":0,"file_total":0,"package_current":0,"package_total":0,"installed":0,"total_files":0,"car_update_id":297,"ecu":"","msg":"package_download_complete","err":-15}}`,
				},
				MockRedisGetSet: testGetSetResult,
			},
		},
		{
			Name: "[TREX] download_failed",
			RedisTestCase: tester.RedisTestCase{
				Device:      common.TRex,
				DeviceKey:   testVIN,
				PayloadData: `{"car_update_id":297,"ecu":"TEST","file_current":0,"file_total":100,"package_current":0,"package_total":1000,"msg":"download_failed","err":0}`,
				ExpectedCaches: map[string]tester.ExpiringCacheResult{
					carupdateKey: {
						Value:   `{"current_size":0,"ecu":"TEST","errorcode":0,"file_size":0,"file_total":100,"id":297,"installed":0,"status":"download_failed","total_files":0,"total_size":1000}`,
						Expires: expectedExpire,
					},
				},
				ExpectedMessages: map[string]string{
					mobile1Key: `{"handler":"car_update_status","data":{"vin":"JH4KA7680RC01","file_current":0,"file_total":100,"package_current":0,"package_total":1000,"installed":0,"total_files":0,"car_update_id":297,"ecu":"TEST","msg":"download_failed","err":0}}`,
					mobile2Key: `{"handler":"car_update_status","data":{"vin":"JH4KA7680RC01","file_current":0,"file_total":100,"package_current":0,"package_total":1000,"installed":0,"total_files":0,"car_update_id":297,"ecu":"TEST","msg":"download_failed","err":0}}`,
					hmiKey:     `{"handler":"car_update_status","data":{"file_current":0,"file_total":100,"package_current":0,"package_total":1000,"installed":0,"total_files":0,"car_update_id":297,"ecu":"TEST","msg":"download_failed","err":0}}`,
				},
				MockRedisGetSet: testGetSetResult,
			},
		},
		{
			Name: "[TREX] install_started",
			RedisTestCase: tester.RedisTestCase{
				Device:      common.TRex,
				DeviceKey:   testVIN,
				PayloadData: `{"car_update_id":297,"ecu":"TEST","installed":0,"total_files":10,"msg":"install_started","err":0}`,
				ExpectedCaches: map[string]tester.ExpiringCacheResult{
					carupdateKey: {
						Value:   `{"current_size":0,"ecu":"TEST","errorcode":0,"file_size":0,"file_total":0,"id":297,"installed":0,"status":"installing","total_files":10,"total_size":0}`,
						Expires: expectedExpire,
					},
				},
				ExpectedMessages: map[string]string{
					mobile1Key: `{"handler":"car_update_status","data":{"vin":"JH4KA7680RC01","file_current":0,"file_total":0,"package_current":0,"package_total":0,"installed":0,"total_files":10,"car_update_id":297,"ecu":"TEST","msg":"installing","err":0}}`,
					mobile2Key: `{"handler":"car_update_status","data":{"vin":"JH4KA7680RC01","file_current":0,"file_total":0,"package_current":0,"package_total":0,"installed":0,"total_files":10,"car_update_id":297,"ecu":"TEST","msg":"installing","err":0}}`,
					hmiKey:     `{"handler":"car_update_status","data":{"file_current":0,"file_total":0,"package_current":0,"package_total":0,"installed":0,"total_files":10,"car_update_id":297,"ecu":"TEST","msg":"installing","err":0}}`,
				},
				MockRedisGetSet: testGetSetResult,
			},
		},
		{
			Name: "[TREX] installing",
			RedisTestCase: tester.RedisTestCase{
				Device:      common.TRex,
				DeviceKey:   testVIN,
				PayloadData: `{"car_update_id":297,"ecu":"TEST","installed":5,"total_files":10,"msg":"installing","err":0}`,
				ExpectedCaches: map[string]tester.ExpiringCacheResult{
					carupdateKey: {
						Value:   `{"current_size":0,"ecu":"TEST","errorcode":0,"file_size":0,"file_total":0,"id":297,"installed":5,"status":"installing","total_files":10,"total_size":0}`,
						Expires: expectedExpire,
					},
				},
				ExpectedMessages: map[string]string{
					mobile1Key: `{"handler":"car_update_status","data":{"vin":"JH4KA7680RC01","file_current":0,"file_total":0,"package_current":0,"package_total":0,"installed":5,"total_files":10,"car_update_id":297,"ecu":"TEST","msg":"installing","err":0}}`,
					mobile2Key: `{"handler":"car_update_status","data":{"vin":"JH4KA7680RC01","file_current":0,"file_total":0,"package_current":0,"package_total":0,"installed":5,"total_files":10,"car_update_id":297,"ecu":"TEST","msg":"installing","err":0}}`,
					hmiKey:     `{"handler":"car_update_status","data":{"file_current":0,"file_total":0,"package_current":0,"package_total":0,"installed":5,"total_files":10,"car_update_id":297,"ecu":"TEST","msg":"installing","err":0}}`,
				},
				MockRedisGetSet: testGetSetResult,
			},
		},
		{
			Name: "[TREX] install_succeeded ECU",
			RedisTestCase: tester.RedisTestCase{
				Device:      common.TRex,
				DeviceKey:   testVIN,
				PayloadData: `{"car_update_id":297,"ecu":"TEST","installed":10,"total_files":10,"msg":"install_succeeded"}`,
				ExpectedCaches: map[string]tester.ExpiringCacheResult{
					carupdateKey: {
						Value:   `{"current_size":0,"ecu":"TEST","errorcode":0,"file_size":0,"file_total":0,"id":297,"installed":10,"status":"package_install_complete","total_files":10,"total_size":0}`,
						Expires: expectedExpire,
					},
				},
				ExpectedMessages: map[string]string{
					mobile1Key: `{"handler":"car_update_status","data":{"vin":"JH4KA7680RC01","file_current":0,"file_total":0,"package_current":0,"package_total":0,"installed":10,"total_files":10,"car_update_id":297,"ecu":"TEST","msg":"package_install_complete","err":0}}`,
					mobile2Key: `{"handler":"car_update_status","data":{"vin":"JH4KA7680RC01","file_current":0,"file_total":0,"package_current":0,"package_total":0,"installed":10,"total_files":10,"car_update_id":297,"ecu":"TEST","msg":"package_install_complete","err":0}}`,
					hmiKey:     `{"handler":"car_update_status","data":{"file_current":0,"file_total":0,"package_current":0,"package_total":0,"installed":10,"total_files":10,"car_update_id":297,"ecu":"TEST","msg":"package_install_complete","err":0}}`,
				},
				MockRedisGetSet: testGetSetResult,
			},
		},
		{
			Name: "[TREX] package_install_complete",
			RedisTestCase: tester.RedisTestCase{
				Device:      common.TRex,
				DeviceKey:   testVIN,
				PayloadData: `{"car_update_id":297,"msg":"install_succeeded","err":0}`,
				ExpectedCaches: map[string]tester.ExpiringCacheResult{
					carupdateKey: {
						Value:   `{"current_size":0,"ecu":"","errorcode":0,"file_size":0,"file_total":0,"id":297,"installed":0,"status":"installing","total_files":0,"total_size":0}`,
						Expires: expectedExpire,
					},
				},
				ExpectedMessages: map[string]string{
					mobile1Key: `{"handler":"car_update_status","data":{"vin":"JH4KA7680RC01","file_current":0,"file_total":0,"package_current":0,"package_total":0,"installed":0,"total_files":0,"car_update_id":297,"ecu":"","msg":"installing","err":0}}`,
					mobile2Key: `{"handler":"car_update_status","data":{"vin":"JH4KA7680RC01","file_current":0,"file_total":0,"package_current":0,"package_total":0,"installed":0,"total_files":0,"car_update_id":297,"ecu":"","msg":"installing","err":0}}`,
					hmiKey:     `{"handler":"car_update_status","data":{"file_current":0,"file_total":0,"package_current":0,"package_total":0,"installed":0,"total_files":0,"car_update_id":297,"ecu":"","msg":"installing","err":0}}`,
				},
				MockRedisGetSet: testGetSetResult,
			},
		},
		{
			Name: "[TREX] install_failed",
			RedisTestCase: tester.RedisTestCase{
				Device:      common.TRex,
				DeviceKey:   testVIN,
				PayloadData: `{"car_update_id":297,"ecu":"TEST","installed":5,"total_files":10,"msg":"install_failed","err":0}`,
				ExpectedCaches: map[string]tester.ExpiringCacheResult{
					carupdateKey: {
						Value:   `{"current_size":0,"ecu":"TEST","errorcode":0,"file_size":0,"file_total":0,"id":297,"installed":5,"status":"install_failed","total_files":10,"total_size":0}`,
						Expires: expectedExpire,
					},
				},
				ExpectedMessages: map[string]string{
					mobile1Key: `{"handler":"car_update_status","data":{"vin":"JH4KA7680RC01","file_current":0,"file_total":0,"package_current":0,"package_total":0,"installed":5,"total_files":10,"car_update_id":297,"ecu":"TEST","msg":"install_failed","err":0}}`,
					mobile2Key: `{"handler":"car_update_status","data":{"vin":"JH4KA7680RC01","file_current":0,"file_total":0,"package_current":0,"package_total":0,"installed":5,"total_files":10,"car_update_id":297,"ecu":"TEST","msg":"install_failed","err":0}}`,
					hmiKey:     `{"handler":"car_update_status","data":{"file_current":0,"file_total":0,"package_current":0,"package_total":0,"installed":5,"total_files":10,"car_update_id":297,"ecu":"TEST","msg":"install_failed","err":0}}`,
				},
				MockRedisGetSet: testGetSetResult,
			},
		},
		{
			Name: "[TREX] requirements_failed",
			RedisTestCase: tester.RedisTestCase{
				Device:      common.TRex,
				DeviceKey:   testVIN,
				PayloadData: `{"car_update_id":297,"ecu":"TEST","installed":5,"total_files":10,"msg":"requirements_failed","err":0}`,
				ExpectedCaches: map[string]tester.ExpiringCacheResult{
					carupdateKey: {
						Value:   `{"current_size":0,"ecu":"TEST","errorcode":0,"file_size":0,"file_total":0,"id":297,"installed":5,"status":"requirements_failed","total_files":10,"total_size":0}`,
						Expires: expectedExpire,
					},
				},
				ExpectedMessages: map[string]string{
					mobile1Key: `{"handler":"car_update_status","data":{"vin":"JH4KA7680RC01","file_current":0,"file_total":0,"package_current":0,"package_total":0,"installed":5,"total_files":10,"car_update_id":297,"ecu":"TEST","msg":"requirements_failed","err":0}}`,
					mobile2Key: `{"handler":"car_update_status","data":{"vin":"JH4KA7680RC01","file_current":0,"file_total":0,"package_current":0,"package_total":0,"installed":5,"total_files":10,"car_update_id":297,"ecu":"TEST","msg":"requirements_failed","err":0}}`,
					hmiKey:     `{"handler":"car_update_status","data":{"file_current":0,"file_total":0,"package_current":0,"package_total":0,"installed":5,"total_files":10,"car_update_id":297,"ecu":"TEST","msg":"requirements_failed","err":0}}`,
				},
				MockRedisGetSet: testGetSetResult,
			},
		},
		{
			Name: "[TREX] install_scheduled ECU",
			RedisTestCase: tester.RedisTestCase{
				Device:      common.TRex,
				DeviceKey:   testVIN,
				PayloadData: `{"car_update_id":297,"ecu":"TEST","installed":10,"total_files":10,"msg":"install_scheduled"}`,
				ExpectedCaches: map[string]tester.ExpiringCacheResult{
					carupdateKey: {
						Value:   `{"current_size":0,"ecu":"TEST","errorcode":0,"file_size":0,"file_total":0,"id":297,"installed":10,"status":"install_scheduled","total_files":10,"total_size":0}`,
						Expires: expectedExpire,
					},
				},
				ExpectedMessages: map[string]string{
					mobile1Key: `{"handler":"car_update_status","data":{"vin":"JH4KA7680RC01","file_current":0,"file_total":0,"package_current":0,"package_total":0,"installed":10,"total_files":10,"car_update_id":297,"ecu":"TEST","msg":"install_scheduled","err":0}}`,
					mobile2Key: `{"handler":"car_update_status","data":{"vin":"JH4KA7680RC01","file_current":0,"file_total":0,"package_current":0,"package_total":0,"installed":10,"total_files":10,"car_update_id":297,"ecu":"TEST","msg":"install_scheduled","err":0}}`,
					hmiKey:     `{"handler":"car_update_status","data":{"file_current":0,"file_total":0,"package_current":0,"package_total":0,"installed":10,"total_files":10,"car_update_id":297,"ecu":"TEST","msg":"install_scheduled","err":0}}`,
				},
				MockRedisGetSet: testGetSetResult,
			},
		},
		{
			Name: "[TREX] manifest_succeeded",
			RedisTestCase: tester.RedisTestCase{
				Device:      common.TRex,
				DeviceKey:   testVIN,
				PayloadData: `{"car_update_id":297,"ecu":"TEST","installed":10,"total_files":10,"msg":"manifest_succeeded"}`,
				ExpectedCaches: map[string]tester.ExpiringCacheResult{
					carupdateKey: {
						Value:   `{"current_size":0,"ecu":"TEST","errorcode":0,"file_size":0,"file_total":0,"id":297,"installed":10,"status":"manifest_succeeded","total_files":10,"total_size":0}`,
						Expires: expectedExpire,
					},
				},
				ExpectedMessages: map[string]string{
					mobile1Key:        `{"handler":"car_update_status","data":{"vin":"JH4KA7680RC01","file_current":0,"file_total":0,"package_current":0,"package_total":0,"installed":10,"total_files":10,"car_update_id":297,"ecu":"TEST","msg":"manifest_succeeded","err":0}}`,
					mobile2Key:        `{"handler":"car_update_status","data":{"vin":"JH4KA7680RC01","file_current":0,"file_total":0,"package_current":0,"package_total":0,"installed":10,"total_files":10,"car_update_id":297,"ecu":"TEST","msg":"manifest_succeeded","err":0}}`,
					hmiKey:            `{"handler":"car_update_status","data":{"file_current":0,"file_total":0,"package_current":0,"package_total":0,"installed":10,"total_files":10,"car_update_id":297,"ecu":"TEST","msg":"manifest_succeeded","err":0}}`,
					"1:JH4KA7680RC01": `{"handler":"read_ecu_versions","data":{"ecu_name":"*"}}`,
				},
				MockRedisGetSet: testGetSetResult,
			},
			SelectCarUpdate: &common.CarUpdate{
				UpdateManifest: &validUpdateManifest,
			},
		},
	}

	for i := range tests {
		mockRedis.Reset()
		test := &tests[i]
		test.SetupRedis(mockRedis)
		test.SetupDB(mockCars, mockCarUpdates, test)

		redisPool := tester.NewMockClientPool(mockRedis)
		handler := controllers.NewCarUpdateProgress(redisPool, mockKeepAwake, mockDB, test.Device)
		if handler == nil {
			t.Error(errors.New("NewCarUpdateProgress cannot handle device %v"))
			continue
		}
		err := handler.Process(test.DeviceKey, []byte(test.PayloadData))

		test.CheckHandlerError(t, test.Name, err)
		test.Validate(t, test.Name, mockRedis)

		for key, m := range test.RedisTestCase.ExpectedMessages {
			name := fmt.Sprintf("%s %s", test.Name, key)
			if strings.Contains(key, "1:") {
				schemaTesterTRex.ValidateSchemaObject(name, []byte(m))
			} else if strings.Contains(key, "2:") {
				schemaTesterHMI.ValidateSchemaObject(name, []byte(m))
			}
		}
	}
}

type FoaServiceMock struct{}

func (f *FoaServiceMock) OtaUpdateStatus(vin string, carUpdate *common.CarUpdate, status *common.CarUpdateProgress) (*http.Response, error) {
	return &http.Response{StatusCode: 200}, nil
}
