package middlewares

import (
	"context"
	"net/http"
	"strconv"
	"strings"

	SOProto "github.com/AlchemyTelcoSolutions/proto/gen/go/callisto/so/v1"
	"github.com/go-chi/chi/v5"
	"google.golang.org/grpc"

	"github.com/AlchemyTelcoSolutions/callisto-so-bff/internal/proxy"
)

// GetOrderRefByLegacyID is a middleware that takes the legacy order id in the URL param, calls the callisto-so service
// to get the new order reference and replaces the legacy order id in the URL param with the new order reference
func GetOrderRefByLegacyID(callistoSOGrpcClient grpc.ClientConnInterface) func(next http.Handler) http.Handler {
	return func(next http.Handler) http.Handler {
		fn := func(w http.ResponseWriter, r *http.Request) {
			if chi.URLParam(r, "order_reference") != "" {
				if legacyOrderID, err := strconv.Atoi(chi.URLParam(r, "order_reference")); err == nil {
					callistoSoService := SOProto.NewSaleOrderServiceClient(callistoSOGrpcClient)

					res, err := callistoSoService.GetNewReference(r.Context(), &SOProto.GetNewReferenceRequest{
						LegacyId: uint64(legacyOrderID),
					})
					if err != nil {
						// need to use string comparison for now until SOS wraps all errors with commonDomain
						if strings.Contains(err.Error(), "not found") {
							http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
							return
						}
						http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
						return
					}

					r = changeChiContextParam(r, chi.URLParam(r, "order_reference"), res.OrderRef)
				}
			}
			next.ServeHTTP(w, r)
		}
		return http.HandlerFunc(fn)
	}
}

// changeChiContextParam is a function that replaces chi context param
func changeChiContextParam(r *http.Request, oldValue, newValue string) *http.Request {
	chiContext := r.Context().Value(chi.RouteCtxKey).(*chi.Context)
	for i, param := range chiContext.URLParams.Values {
		if param == oldValue {
			chiContext.URLParams.Values[i] = newValue
		}
	}

	// store the original value in context for future reference
	ctx := context.WithValue(r.Context(), proxy.LegacyOrderIDCtxValue{}, oldValue)

	// replace the original value with the new value
	ctx = context.WithValue(ctx, chi.RouteCtxKey, chiContext)

	return r.WithContext(ctx)
}
