package services

import (
	"net/http"
	"net/url"
	"slices"
	"sync"

	"github.com/fiskerinc/cloud-services/pkg/common"
	s "github.com/fiskerinc/cloud-services/pkg/common/carupdatestatus"
	"github.com/fiskerinc/cloud-services/pkg/foa"
	"github.com/fiskerinc/cloud-services/pkg/httpclient"
	"github.com/fiskerinc/cloud-services/pkg/logger"
	"github.com/fiskerinc/cloud-services/pkg/utils/envtool"
)

var UPDATE_MANIFEST_IDS_TO_NOTIFY_FOA = []int64{816, 817, 818, 819, 820}

var (
	foaService FoaServiceInterface
	foaOnce    sync.Once
)

func GetFoaService() FoaServiceInterface {
	foaOnce.Do(func() {
		if foaService != nil {
			return
		}
		foaService = NewFoaService()
	})

	return foaService
}

func SetFoaService(foa FoaServiceInterface) {
	foaService = foa
}

func NewFoaService() FoaServiceInterface {
	return &FoaService{
		foaURL:      envtool.GetEnv("FOA_URL", "REPLACE_ME"),
		foaAPIToken: envtool.GetEnv("FOA_API_KEY", "REPLACE_ME"),
	}
}

type FoaServiceInterface interface {
	OtaUpdateStatus(vin string, carUpdate *common.CarUpdate, status *common.CarUpdateProgress) (*http.Response, error)
}

type FoaService struct {
	foaURL      string
	foaAPIToken string
}

func (f *FoaService) OtaUpdateStatus(vin string, carUpdate *common.CarUpdate, status *common.CarUpdateProgress) (*http.Response, error) {
	if !slices.Contains(UPDATE_MANIFEST_IDS_TO_NOTIFY_FOA, carUpdate.UpdateManifestID) {
		// Nothing to send if the manifest is not one of the specified IDs
		return nil, nil
	}

	var body interface{} = nil

	switch status.Status {
	case s.ManifestSucceeded:
		body = foa.BuildOtaUpdateStatusSuccessRequest(vin, carUpdate.UpdateManifestID)
	case s.ManifestError:
		body = foa.BuildOtaUpdateStatusFailedRequest(vin, carUpdate.UpdateManifestID, status.Info)
	case s.ManifestCanceled:
		body = foa.BuildOtaUpdateStatusCanceledRequest(vin, carUpdate.UpdateManifestID, status.Info)
	}

	if body == nil {
		return nil, nil
	}

	logger.Info().Msgf("Notifying FOA for %s of update %d status %s", vin, carUpdate.UpdateManifestID, status.Status)

	urlString, err := url.JoinPath(f.foaURL, "ota/update_status")
	if err != nil {
		return nil, err
	}

	postHeader := http.Header{}
	postHeader.Add("Authorization", "Bearer "+f.foaAPIToken)
	postHeader.Add("Content-Type", "application/json")

	return httpclient.Post(urlString, body, postHeader)
}
