package handlers

import (
	"context"
	"encoding/json"
	"fmt"
	"strings"

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

	"github.com/fiskerinc/cloud-services/pkg/common"
	"github.com/fiskerinc/cloud-services/pkg/grpc/sms"
	"github.com/fiskerinc/cloud-services/pkg/logger"
	"github.com/fiskerinc/cloud-services/pkg/manifestsender"
	"github.com/fiskerinc/cloud-services/pkg/tmobile"
	"github.com/fiskerinc/cloud-services/pkg/utils/envtool"
)

var ENABLE_ORDERUPDATE_SENDS = envtool.GetEnvBool("ENABLE_ORDERUPDATE_SENDS", false)

// Take the feature codes from VehicleOrder message to generate the VOD and CDSs
// Create a new common.UpdateManifest with the VOD and CDS and save it as a common.ConfigUpdateType
// Create a new common.CarUpdate for the VIN and the manifest in step 2 and save it to the database
// Copy the car update id into the UpdateManifest
// Send the UpdateManifest to both trex and hmi
func OrderUpdated(db *services.DB, smsClient sms.SMSServiceClient, vin string, data []byte) error {
	logger.Debug().Msgf("Order updated %s", vin)

	var order common.VehicleOrder
	err := json.Unmarshal(data, &order)
	if err != nil {
		return err
	}

	err = setCarSettings(db, vin, order)
	if err != nil {
		return err
	}

	err = changeRatePlan(db, smsClient, vin, order.VehicleSpecification.DestinationCountry)
	if err != nil {
		logger.Error().Msgf("Failed to change rate plan for %s, %s", vin, err)
	}

	if !ENABLE_ORDERUPDATE_SENDS {
		return nil
	}

	cs := services.GetVehicleConfig()
	r := services.RedisClientPool().GetFromPool()
	defer r.Close()

	trex := manifestsender.NewTBOXManifestSender(r, cs, services.GetDB(), nil, nil)
	defer trex.Close()

	// I don't think this has ever been called on production, or dev !
	input := manifestsender.ProcessConfigUpdateStruct{
		VIN:                     vin,
		Name:                    "SAP order change update",
		Username:                "unidentified attendant sap user",
		SendToCar:               true,
		DontCreateDatabaseEntry: false,
		Forced:                  false,
	}
	_, err = trex.ProcessConfigUpdate(input, services.GetDB().GetCarConfigData())

	return err
}

func setCarSettings(db *services.DB, vin string, order common.VehicleOrder) (err error) {
	// If the sequence number is missing, go will fill it in as 0, which is the case where the car has no sequence number
	if order.VehicleSpecification.SequenceNumber != "" {
		_, err = db.GetCars().SetSetting(&common.CarSetting{
			VIN:   vin,
			Name:  common.SEQUENCE_NUMBER,
			Value: fmt.Sprint(order.VehicleSpecification.SequenceNumber),
			Type:  "string",
		})
		if err != nil {
			return err
		}
	}

	_, err = db.GetCars().SetSetting(&common.CarSetting{
		VIN:   vin,
		Name:  common.BODY_COLOR,
		Value: common.FeatureCodeToBodyColor(order.VehicleSpecification.VehicleFeatures),
		Type:  "string",
	})
	if err != nil {
		return err
	}

	// Incase SAP hasn't sent this value yet
	if order.VehicleSpecification.DestinationCountry != "" {
		_, err = db.GetCars().SetSetting(&common.CarSetting{
			VIN:   vin,
			Name:  common.DELIVERY_DESTINATION,
			Value: order.VehicleSpecification.DestinationCountry,
			Type:  "string",
		})
		if err != nil {
			return err
		}
	}

	return
}

func changeRatePlan(db *services.DB, smsClient sms.SMSServiceClient, vin, destinationCountry string) error {
	car, err := services.GetDB().GetCars().SelectByVIN(vin)
	if err != nil {
		return err
	}

	if len(car.ICCID) == 0 {
		return fmt.Errorf("no iccid found for vehicle %s", vin)
	}
	iccid := strings.TrimSuffix(strings.ToLower(car.ICCID), "f")

	customAtributeReq := sms.CustomAtributesRequest{
		ICCID:          iccid,
		AccountCustom1: destinationCountry,
	}
	_, err = smsClient.HandleCustomAttributes(context.Background(), &customAtributeReq)
	if err != nil {
		return err
	}

	ratePlan, err := db.GetRatePlan().Select(destinationCountry)
	if err != nil {
		return err
	}
	changeRatePlanRequest := sms.ChangeRatePlanRequest{
		ICCID:     iccid,
		ProductId: ratePlan.ProductID,
		AccountId: tmobile.FISKER_TMOBILE_ACCOUNT_ID,
	}
	_, err = smsClient.HandleChangeRatePlan(context.Background(), &changeRatePlanRequest)
	if err != nil {
		return err
	}

	go verifyRatePlan(smsClient, iccid, destinationCountry)
	return nil
}

func verifyRatePlan(smsClient sms.SMSServiceClient, iccid, destinationCountry string) error {
	deviceDetailsRequest := sms.DeviceDetailsRequest{
		ICCID: iccid,
	}

	details, err := smsClient.HandleDeviceDetails(context.Background(), &deviceDetailsRequest)
	if err != nil {
		logger.Error().Msgf("failed to check device details for iccid %s", iccid)
	}

	logger.Info().Msgf("device details for iccid %s: %+v", iccid, details)
	return nil
}
