package queries_test

import (
	"fmt"
	"testing"
	"time"

	"github.com/fiskerinc/cloud-services/pkg/common"
	"github.com/fiskerinc/cloud-services/pkg/db"
	"github.com/fiskerinc/cloud-services/pkg/db/queries"
	"github.com/fiskerinc/cloud-services/pkg/testhelper"
)

func TestUpdatePackagesManifest(t *testing.T) {
	t.Skip()
	query := setupUpdateManifest(t)
	manifestID := insertUpdateManifest(t, query)
	if manifestID == 0 {
		t.Error("setup failed")
		return
	}
	selectUpdateManifest(t, query, manifestID)
	searchUpdateManifest(t, query, manifestID)
	updateUpdateManifest(t, query, manifestID)
	archiveUpdateManifest(t, query, []int64{manifestID}, true)
	deleteUpdateManifest(t, query, manifestID)
}

func setupUpdateManifest(t *testing.T) queries.UpdateManifestsInterface {
	instance := queries.NewUpdateManifest(nil)
	conn := instance.GetDBConn()
	conn.AddQueryHook(db.SQLLogger{})

	client := instance.GetClient()
	client.InitSchema([]interface{}{
		(*common.UpdateManifest)(nil),
		(*common.UpdateManifestECU)(nil),
		(*common.UpdateManifestFile)(nil),
		(*common.MemoryRegion)(nil),
	})

	return instance
}

func insertUpdateManifest(t *testing.T, query queries.UpdateManifestsInterface) int64 {
	expectedRows := 20
	manifest := common.UpdateManifest{
		Name:            fmt.Sprintf("NAME %s", time.Now().String()),
		Version:         "VERSION",
		Description:     "DESCRIPTION",
		ReleaseNotes:    "RELEASENOTES",
		RollbackEnabled: true,
		Type:            "standard",
		Fingerprint:     "10203040",
		Country:         "US",
		PowerTrain:      "MD23",
		Restraint:       "None",
		Model:           "Ocean",
		Trim:            "Sport",
		Year:            2022,
		BodyType:        "truck",
		ECUs: []*common.UpdateManifestECU{
			{
				ECU:               "ECU",
				Version:           "VERSION",
				HWVersion:         "BIGBADVERSION",
				HWVersions:        []string{"HWVERSION"},
				ConfigurationMask: "CONFIGURATIONMASK",
				Mode:              "D",
				SelfDownload:      true,
				Files: []*common.UpdateManifestFile{
					{
						FileID:        "FILEID",
						URL:           "URL",
						Filename:      "FILENAME",
						FileSize:      5,
						Checksum:      "CHECKSUM",
						FileType:      "bootloader",
						FileOrder:     9,
						WriteRegionID: 100,
						WriteRegion: common.MemoryRegion{
							Offset: 101,
							Length: 102,
						},
						EraseRegionID: 200,
						EraseRegion: &common.MemoryRegion{
							Offset: 201,
							Length: 202,
						},
					},
				},
			},
		},
	}
	result, err := query.Insert(&manifest)
	if err != nil {
		t.Errorf(testhelper.TestErrorTemplate, "UpdateManifest insert", nil, err)
		return 0
	}

	if result.RowsAffected() != expectedRows {
		t.Errorf(testhelper.TestErrorTemplate, "UpdateManifest insert RowsAffected", expectedRows, result.RowsAffected())
	}
	if result.RowsReturned() != expectedRows {
		// file insert does not return row
		t.Errorf(testhelper.TestErrorTemplate, "UpdateManifest insert RowsReturned", expectedRows, result.RowsReturned())
	}

	return manifest.ID
}

func selectUpdateManifest(t *testing.T, query queries.UpdateManifestsInterface, manifestID int64) {
	manifest := common.UpdateManifest{ID: manifestID}
	err := query.Load(&manifest)
	if err != nil {
		t.Errorf(testhelper.TestErrorTemplate, "UpdateManifest Load", nil, err)
	}
	if manifest.Name == "" {
		t.Errorf(testhelper.TestErrorTemplate, "UpdateManifest Load Name", "not empty", manifest.Name)
	}

	manifestValues := map[string]interface{}{
		"Version":         "VERSION",
		"Description":     "DESCRIPTION",
		"ReleaseNotes":    "RELEASENOTES",
		"RollbackEnabled": true,
		"Type":            "standard",
		"Fingerprint":     "10203040",
	}
	testhelper.PropsTester(t, &manifest, manifestValues)
	if len(manifest.ECUs) != 1 {
		t.Errorf(testhelper.TestErrorTemplate, "UpdateManifest Load ECUs", 1, len(manifest.ECUs))
	} else {
		ecu := manifest.ECUs[0]
		ecuValues := map[string]interface{}{
			"ECU":               "ECU",
			"Version":           "VERSION",
			"HWVersion":         "",
			"HWVersions":        []string{"HWVERSION"},
			"ConfigurationMask": "CONFIGURATIONMASK",
			"Mode":              "D",
			"SelfDownload":      true,
		}
		testhelper.PropsTester(t, ecu, ecuValues)

		if len(ecu.Files) != 1 {
			t.Errorf(testhelper.TestErrorTemplate, "UpdateManifest Load Files", 1, len(ecu.Files))
		} else {
			file := ecu.Files[0]
			fileValues := map[string]interface{}{
				"FileID":    "FILEID",
				"URL":       "URL",
				"Filename":  "FILENAME",
				"FileSize":  uint64(5),
				"Checksum":  "CHECKSUM",
				"FileType":  "bootloader",
				"FileOrder": 9,
			}
			testhelper.PropsTester(t, file, fileValues)
		}
	}

	manifests, err := query.Select(&common.UpdateManifest{ID: manifestID}, nil)
	if err != nil {
		t.Errorf(testhelper.TestErrorTemplate, "UpdateManifest Select", nil, err)
	}
	if len(manifests) != 1 {
		t.Errorf(testhelper.TestErrorTemplate, "UpdateManifest Select count", 1, len(manifests))
	} else {
		testhelper.PropsTester(t, &manifests[0], manifestValues)
	}

	count, err := query.Count(common.UpdateManifest{ID: manifestID})
	if err != nil {
		t.Errorf(testhelper.TestErrorTemplate, "UpdateManifest Count", nil, err)
	}
	if count != 1 {
		t.Errorf(testhelper.TestErrorTemplate, "UpdateManifest Count", 1, count)
	}
}

func archiveUpdateManifest(t *testing.T, query queries.UpdateManifestsInterface, ids []int64, active bool) {
	result, err := query.Archive(ids, active)
	if err != nil {
		t.Errorf(testhelper.TestErrorTemplate, "UpdateManifest archive", nil, err)
		return
	}

	if result.RowsAffected() != 1 {
		t.Errorf(testhelper.TestErrorTemplate, "UpdateManifest archive RowsAffected", 1, result.RowsAffected())
	}

	if result.RowsReturned() != 0 {
		t.Errorf(testhelper.TestErrorTemplate, "UpdateManifest archive RowsReturned", 0, result.RowsReturned())
	}
}

func searchUpdateManifest(t *testing.T, query queries.UpdateManifestsInterface, manifestID int64) {
	manifest := common.UpdateManifest{ID: manifestID}
	err := query.Load(&manifest)
	if err != nil {
		t.Errorf(testhelper.TestErrorTemplate, "UpdateManifest Search Load", nil, err)
	}

	search := common.UpdateManifestSearch{
		Search: manifest.Name,
	}
	manifests, err := query.Search(search, nil)
	if err != nil {
		t.Errorf(testhelper.TestErrorTemplate, "UpdateManifest Search", nil, err)
	}
	if len(manifests) == 0 {
		t.Errorf(testhelper.TestErrorTemplate, "UpdateManifest Search len", "gt 0", len(manifests))
	}

	count, err := query.SearchCount(search)
	if err != nil {
		t.Errorf(testhelper.TestErrorTemplate, "UpdateManifest SearchCount", nil, err)
	}
	if count == 0 {
		t.Errorf(testhelper.TestErrorTemplate, "UpdateManifest SearchCount count", "gt 0", count)
	}
}

func updateUpdateManifest(t *testing.T, query queries.UpdateManifestsInterface, manifestID int64) {
	manifest := common.UpdateManifest{ID: manifestID}
	err := query.Load(&manifest)
	if err != nil {
		t.Errorf(testhelper.TestErrorTemplate, "UpdateManifest Update Load", nil, err)
	}

	manifest.Type = "forced"
	manifest.Name = "some very nice update"
	result, err := query.Update(&manifest)
	if err != nil {
		t.Errorf(testhelper.TestErrorTemplate, "UpdateManifest Update", nil, err)
		return
	}
	if result.RowsAffected() != 1 {
		t.Errorf(testhelper.TestErrorTemplate, "UpdateManifest Update RowsAffected", 1, result.RowsAffected())
	}
	if result.RowsReturned() != 0 {
		t.Errorf(testhelper.TestErrorTemplate, "UpdateManifest Update RowsReturned", 0, result.RowsReturned())
	}

	manifest = common.UpdateManifest{ID: manifestID}
	err = query.Load(&manifest)
	if err != nil {
		t.Errorf(testhelper.TestErrorTemplate, "UpdateManifest Update Reload", nil, err)
	}
	if manifest.Type != "forced" && manifest.Name != "some very nice update" {
		t.Errorf(
			testhelper.TestErrorTemplate,
			"UpdateManifest Update",
			"forced, some very nice update",
			fmt.Sprintf("%s, %s", manifest.Type, manifest.Name))
	}

}

func deleteUpdateManifest(t *testing.T, query queries.UpdateManifestsInterface, manifestID int64) {
	result, err := query.Delete(&common.UpdateManifest{ID: manifestID})
	if err != nil {
		t.Errorf(testhelper.TestErrorTemplate, "UpdateManifest delete", nil, err)
		return
	}

	// Used to be 15 as the delete wasn't cascaded and the count of rows deletes was the total of all the deletes being ran
	if result.RowsAffected() != 1 {
		t.Errorf(testhelper.TestErrorTemplate, "UpdateManifest delete RowsAffected", 1, result.RowsAffected())
	}

	if result.RowsReturned() != 0 {
		t.Errorf(testhelper.TestErrorTemplate, "UpdateManifest delete RowsReturned", 0, result.RowsReturned())
	}
}

// Testing to see if ECURollbakcs query works successfully on the database
func TestECURollbacks(t *testing.T) {
	t.Skip()
	vin := "VCF1ZBU28PG003392"
	instance := queries.NewUpdateManifest(nil)

	man := common.UpdateManifestECU{
		ECU: "ICC",
	}
	res, err := instance.ECURollback(&man, vin)
	if err != nil {
		t.Error(err)
	}
	if len(res) != 1{
		t.Logf("Rollback length wrong: expected 1 got %d", len(res))
		t.Fail()
	}
}

func TestManifestSearch(t *testing.T){
	t.Skip()
	filter := common.UpdateManifestSearch{}
	filter.ManifestType = common.AftersalesUpdateType

	paging := queries.PageQueryOptions{
		Order:  "id DESC",
		Limit:  5,
		Offset: 0,
	}

	query := setupUpdateManifest(t)
	_, err := query.Search(filter, &paging)
	if err != nil {
		t.Error(err)
	}
}
