package handlers

import (
	"encoding/json"
	"net/http"
	"otaupdate/services"

	"github.com/fiskerinc/cloud-services/pkg/common"
	"github.com/fiskerinc/cloud-services/pkg/logger"
	"github.com/fiskerinc/cloud-services/pkg/utils"
	"github.com/pkg/errors"
	"github.com/fiskerinc/cloud-services/pkg/loggerdataresp"
)

// HandleUpdateManifestRawPost godoc
// @Summary Receive the raw information and load it into the database
// @Description Get update manifest by id, without modifying anything from the database
// @Accept  json
// @Produce  json
// @Param Authorization header string false "Bearer <ID token>"
// @Param Api-Key header string false "<API token>"
// @Param data body ManifestMigrateBody true "The manifest to migrate"
// @Success 200 {object} common.JSONMessage
// @Failure 400 {object} common.JSONError "Bad request"
// @Failure 401 {object} common.JSONError "Unauthorized"
// @Failure 503 {object} common.JSONError "Service unavailable"
// @Router /manifestmigrate [post]
func HandleUpdateManifestMigrateReceive(w http.ResponseWriter, r *http.Request) {
	var err error
	var migratedManifest common.UpdateManifest
	var migrateBody ManifestMigrateBody

	if r.Body == nil {
		err = errors.New("HandleUpdateManifestMigrateReceive received a null body")
		loggerdataresp.BadDataErrorResp(w, err, http.StatusBadRequest)
		return
	}

	err = json.NewDecoder(r.Body).Decode(&migrateBody)
	err = errors.WithStack(err)
	if loggerdataresp.BadDataErrorResp(w, err, http.StatusBadRequest) {
		return
	}

	cleansIDS(&migrateBody)
	migratedManifest = migrateBody.MigratedManifest
	um := services.GetDB().GetUpdateManifests()
	_, err = um.Insert(&migratedManifest)
	if loggerdataresp.BadDataErrorResp(w, err, http.StatusBadRequest) {
		logger.Err(err).Interface("migrated_manifest", migrateBody).Msg("Failed to insert migrated manifest")
		return
	}
	//vscode://file/Users/alexanderandrews/Documents/project-ai2/cloud/modules_go/db/queries/filekeys.go:52
	// Insert the unencrypted file keys, as the insert command encrypts them for us
	dbFK := services.GetDB().GetFileKeys()
	for _, fkr := range migrateBody.FileKeys {
		fileKey := common.FileKey{}
		err = fileKey.Apply(&fkr)
		if err != nil {
			newErr := rollbackManifestMigrate(&migratedManifest)
			if newErr != nil {
				err = errors.Wrap(err, newErr.Error())
			}
			loggerdataresp.BadDataErrorResp(w, err, http.StatusBadRequest)
			return
		}
		_, err = dbFK.Insert(fileKey)

		if err != nil {
			newErr := rollbackManifestMigrate(&migratedManifest)
			if newErr != nil {
				err = errors.Wrap(err, newErr.Error())
			}
			loggerdataresp.BadDataErrorResp(w, err, http.StatusBadRequest)
			return
		}
	}
	utils.RespJSON(w, http.StatusOK, common.JSONMessage{
		Message: "Migration Received",
	})
}

// THIS wil need changing
// If the manifest keys fail to upload, we should delete the manifest
func rollbackManifestMigrate(manifest *common.UpdateManifest) (err error) {
	um := services.GetDB().GetUpdateManifests()
	_, err = um.Delete(manifest)
	return
}

type ManifestMigrateBody struct {
	MigratedManifest common.UpdateManifest
	FileKeys         []common.FileKeyResponse
}

func cleansIDS(migrateBody *ManifestMigrateBody) {
	hold := migrateBody.MigratedManifest
	hold.ID = 0
	hold.CarUpdateID = 0
	for x, ecu := range hold.ECUs {
		ecu.ID = 0
		ecu.UpdateManifestID = 0
		for y, file := range ecu.Files {
			file.UpdateManifestECUID = 0
			ecu.Files[y] = file
		}
		hold.ECUs[x] = ecu
	}
	migrateBody.MigratedManifest = hold
}
