package handlers

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

	"github.com/fiskerinc/cloud-services/pkg/grpc/sms"
	"github.com/pkg/errors"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
	"google.golang.org/protobuf/encoding/protojson"
	"github.com/fiskerinc/cloud-services/pkg/loggerdataresp"
)

// HandleSMSSend godoc
// @Summary Send SMS
// @Description Send SMS using SMS service
// @Accept  json
// @Produce  json
// @Param Authorization header string false "Bearer <ID token>"
// @Param Api-Key header string false "<API token>"
// @Param config body sms.SendSMSRequest true "SMS data"
// @Success 200 {object} sms.SMSDetailsResponse
// @Failure 400 {object} common.JSONError "Bad request"
// @Failure 401 {object} common.JSONError "Unauthorized"
// @Failure 408 {object} common.JSONError "Request timeout"
// @Failure 503 {object} common.JSONError "Service unavailable"
// @Router /sms [post]
func HandleSMSSend(w http.ResponseWriter, r *http.Request) {
	var smsReq sms.SendSMSRequest
	if err := json.NewDecoder(r.Body).Decode(&smsReq); err != nil {
		loggerdataresp.BadDataErrorResp(w, err, http.StatusBadRequest)
		return
	}

	res, err := services.GetSMSClient().HandleSMSSend(r.Context(), &smsReq)
	if err != nil {
		s, ok := status.FromError(err)
		if !ok {
			loggerdataresp.BadDataErrorResp(w, err, http.StatusInternalServerError)
			return
		}

		errMsg, httpCode := grpcErrToHttpErr(s)
		loggerdataresp.BadDataErrorResp(w, errors.New(errMsg), httpCode)
		return
	}

	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(http.StatusOK)

	tow, err := protojson.Marshal(res)
	if loggerdataresp.BadDataErrorResp(w, err, http.StatusBadRequest) {
		return
	}

	w.Write(tow)

	return
}

func grpcErrToHttpErr(s *status.Status) (string, int) {
	switch s.Code() {
	case codes.Canceled:
		return s.Message(), 499
	case codes.Unknown:
		return s.Message(), http.StatusInternalServerError
	case codes.InvalidArgument:
		return s.Message(), http.StatusBadRequest
	case codes.DeadlineExceeded:
		return s.Message(), http.StatusRequestTimeout
	case codes.NotFound:
		return s.Message(), http.StatusNotFound
	case codes.AlreadyExists:
		return s.Message(), http.StatusConflict
	case codes.PermissionDenied:
		return s.Message(), http.StatusForbidden
	case codes.ResourceExhausted:
		return s.Message(), http.StatusTooManyRequests
	case codes.FailedPrecondition:
		return s.Message(), http.StatusPreconditionFailed
	case codes.Aborted:
		return s.Message(), http.StatusConflict
	case codes.OutOfRange:
		return s.Message(), http.StatusBadRequest
	case codes.Unimplemented:
		return s.Message(), http.StatusNotImplemented
	case codes.Unavailable:
		return s.Message(), http.StatusServiceUnavailable
	case codes.DataLoss:
		return s.Message(), http.StatusInternalServerError
	case codes.Unauthenticated:
		return s.Message(), http.StatusUnauthorized
	case codes.Internal:
		if strings.Contains(s.Message(), "bad message status") {
			return s.Message(), http.StatusExpectationFailed
		}

		return s.Message(), http.StatusInternalServerError
	default:
		return s.Message(), http.StatusInternalServerError
	}
}
