package handlers

import (
	"encoding/json"
	"net/http"
	"otaupdate/utils"
	"time"

	"github.com/fiskerinc/cloud-services/pkg/common"
	"github.com/fiskerinc/cloud-services/pkg/logger"
	"github.com/fiskerinc/cloud-services/pkg/remotefileupload"
	"github.com/Azure/azure-storage-blob-go/azblob"
	"github.com/julienschmidt/httprouter"
	"github.com/pkg/errors"
	"github.com/fiskerinc/cloud-services/pkg/loggerdataresp"
)

// Need this so the swagger can use m
var _ = common.APIToken{}

// HandleTrexLogsLinkGet godoc
// @Summary Retrieve T.Rex logs
// @Description Get T.Rex logs for specific day
// @Accept  json
// @Produce  json
// @Param Authorization header string false "Bearer <ID token>"
// @Param Api-Key header string false "<API token>"
// @Param vin path string true "Car vin"
// @Param year query string true "Year of file"
// @Param month query string true "Month of file"
// @Param day query string true "Day of file"
// @Success 200 {object} LinkResponse
// @Failure 400 {object} common.JSONError "Bad request"
// @Failure 401 {object} common.JSONError "Unauthorized"
// @Failure 404 {object} common.JSONError "Status not found"
// @Failure 503 {object} common.JSONError "Service unavailable"
// @Router /vehicle/{vin}/trex-logs-link [get]
func HandleTrexLogsLinkGet(w http.ResponseWriter, r *http.Request) {
	params := httprouter.ParamsFromContext(r.Context())
	vin := params.ByName("vin")
	query := r.URL.Query()
	year := query.Get("year")
	month := query.Get("month")
	day := query.Get("day")
	if vin == "" || year == "" || month == "" || day == "" {
		http.Error(w, "incomplete parameters", http.StatusBadRequest)
		return
	}
	// We are trusting the date is good, otherwise the user will get a download to nothing
	str, err := getAzureTRexBlobLink(vin, year, month, day)
	if loggerdataresp.BadDataErrorResp(w, err, http.StatusBadRequest) {
		return
	}

	encoder := json.NewEncoder(w)
	encoder.SetEscapeHTML(false) // Otherwise & becomes /00 encoded
	err = encoder.Encode(LinkResponse{Link: str})
	if loggerdataresp.BadDataErrorResp(w, err, http.StatusBadRequest) {
		return
	}
}

type LinkResponse struct {
	Link string
}

func getAzureTRexBlobLink(vin, year, month, day string) (link string, err error) {
	link, err = remotefileupload.AzureFilePathLink(utils.AzureAccount, utils.AzureTRexLogsContainerName, vin, year, month, day, "raw.log")
	if err != nil {
		logger.Err(err).Msg("")
	}
	sasToken, err := getSASAccessTokenOnceADay()
	if err != nil {
		logger.Err(err).Msg("")
	}
	return link + "?" + sasToken, err
}

// We will fetch the access token once a day to prevent access to the files if someone saves a link somewhere accidentally
var cachedTokenTime time.Time // The Time we last got the token
var cachedToken string        // Once a day get a new access token

func getSASAccessTokenOnceADay() (token string, err error) {
	if time.Since(cachedTokenTime) > time.Hour*24 {
		cachedTokenTime = time.Now()
		cachedToken, err = generateSASToken()
	}
	return cachedToken, err
}

func generateSASToken() (token string, err error) {
	cred, err := azblob.NewSharedKeyCredential(utils.AzureAccount, utils.AzureAccountKey)
	if err != nil {
		return "", errors.WithStack(err)
	}

	sasQueryParams, err := azblob.BlobSASSignatureValues{
		Protocol:      azblob.SASProtocolHTTPS,
		StartTime:     time.Now().UTC(),
		ExpiryTime:    time.Now().UTC().Add(48 * time.Hour),
		Permissions:   azblob.BlobSASPermissions{Read: true, List: true}.String(),
		IPRange:       azblob.IPRange{},
		ContainerName: utils.AzureTRexLogsContainerName,
	}.NewSASQueryParameters(cred)

	if err != nil {
		logger.Error().Err(err).Msg("Failed to sas.BlobSignatureValues")
		return
	}

	token = sasQueryParams.Encode()
	return
}
