package handlers_test

import (
	"fmt"
	"testing"
	"time"

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

	"github.com/fiskerinc/cloud-services/pkg/common"
	s "github.com/fiskerinc/cloud-services/pkg/common/carupdatestatus"
	"github.com/fiskerinc/cloud-services/pkg/common/dbbasemodel"
	"github.com/fiskerinc/cloud-services/pkg/db/queries/mocks"
	"github.com/fiskerinc/cloud-services/pkg/redis/tester"
	"github.com/pkg/errors"
)

func TestUpdatesGet(t *testing.T) {
	mockRedis := &tester.MockRedis{}
	services.SetRedisClientPool(tester.NewMockClientPool(mockRedis))
	mockCars := &mocks.MockCars{}
	mockCarUpdates := &mocks.MockCarUpdates{}
	mockDB = &services.DB{}
	mockDB.SetCars(mockCars)
	mockDB.SetCarUpdates(mockCarUpdates)

	cognitoID := "valid-cognito-id-1"
	mobileKey := common.Mobile.Key(cognitoID)
	vin := "JM1BG2241R0797923"
	data := fmt.Sprintf(`{"vin":"%s"}`, vin)
	now := time.Now()
	selectList := []common.CarUpdate{
		{
			ID:               1234,
			VIN:              vin,
			UpdateManifestID: 4321,
			Status:           s.InstallApprovalAwait,
			UpdateManifest: &common.UpdateManifest{
				Name:         "TEST",
				Description:  "TEST",
				ReleaseNotes: "http://releasenotes.com",
				Country:      "US",
				PowerTrain:   "MD23",
				Restraint:    "None",
				Model:        "Ocean",
				Trim:         "Sport",
				Year:         2022,
				BodyType:     "truck",
				ECUs: []*common.UpdateManifestECU{
					{
						ECU:     "ADAS",
						Version: "VERSION",
						Mode:    "A",
					},
				},
				DBModelBase: dbbasemodel.DBModelBase{
					CreatedAt: &now,
					UpdatedAt: &now,
				},
			},
		},
	}
	carToDrivers := []common.CarToDriver{
		{
			ID:       2000,
			VIN:      vin,
			DriverID: cognitoID,
		},
	}

	tests := []AttendentRouteTestCase{
		{
			Name: "No data",
			RedisTestCase: tester.RedisTestCase{
				Device:        common.Mobile,
				DeviceKey:     cognitoID,
				PayloadData:   "",
				ExpectedError: "unexpected end of JSON input",
			},
		},
		{
			Name: "Bad request",
			RedisTestCase: tester.RedisTestCase{
				Device:        common.Mobile,
				DeviceKey:     cognitoID,
				PayloadData:   "{}",
				ExpectedError: "Key: 'VehicleData.VIN' Error:Field validation for 'VIN' failed on the 'required' tag",
			},
		},
		{
			Name: "Bad association",
			RedisTestCase: tester.RedisTestCase{
				Device:        common.Mobile,
				DeviceKey:     cognitoID,
				PayloadData:   data,
				ExpectedError: "no relationship found between vin JM1BG2241R0797923 and driver valid-cognito-id-1",
			},
		},
		{
			Name: "Cache error",
			RedisTestCase: tester.RedisTestCase{
				Device:        common.Mobile,
				DeviceKey:     cognitoID,
				PayloadData:   data,
				ExpectedError: "cache error",
			},
			CarToDriversError: errors.New("cache error"),
		},
		{
			Name: "Good request",
			RedisTestCase: tester.RedisTestCase{
				Device:      common.Mobile,
				DeviceKey:   cognitoID,
				PayloadData: data,
				ExpectedMessages: map[string]string{
					mobileKey: `{"handler":"updates","data":[{"id":1234,"vin":"JM1BG2241R0797923","name":"TEST","description":"TEST","release_notes":"http://releasenotes.com"}]}`,
				},
			},
			SelectCarToDrivers: carToDrivers,
			SelectCarUpdates:   selectList,
		},
		{
			Name: "DB error",
			RedisTestCase: tester.RedisTestCase{
				Device:        common.Mobile,
				DeviceKey:     cognitoID,
				PayloadData:   data,
				ExpectedError: "database error",
			},
			SelectCarToDrivers: carToDrivers,
			SelectCarUpdates:   nil,
			CarUpdateError:     errors.New("database error"),
		},
	}

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

		err := handlers.GetUpdates(mockDB, test.DeviceKey, []byte(test.PayloadData))

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