package common

import (
	"expvar"
	"net/http"
	"strconv"
	"sync"

	"github.com/felixge/httpsnoop"
)

var (
	metricsOnce               sync.Once
	metricTotalRequests       *expvar.Int
	metricTotalResponses      *expvar.Int
	metricTotalProcessingTime *expvar.Int
	metricResponsesByStatus   *expvar.Map
)

func (app *Application) Metrics(next http.Handler) http.Handler {
	metricsOnce.Do(func() {
		metricTotalRequests = expvar.NewInt("total_requests_received")
		metricTotalResponses = expvar.NewInt("total_responses_sent")
		metricTotalProcessingTime = expvar.NewInt("total_processing_time_μs")
		metricResponsesByStatus = expvar.NewMap("total_responses_sent_by_status")
	})

	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		metricTotalRequests.Add(1)
		m := httpsnoop.CaptureMetrics(next, w, r)
		metricTotalResponses.Add(1)
		metricTotalProcessingTime.Add(m.Duration.Microseconds())
		metricResponsesByStatus.Add(strconv.Itoa(m.Code), 1)
	})
}

func (app *Application) EnableCORS(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Add("Vary", "Origin")
		w.Header().Add("Vary", "Access-Control-Request-Method")

		origin := r.Header.Get("Origin")
		if origin != "" && len(app.CORSTrustedOrigins) != 0 {
			for i := range app.CORSTrustedOrigins {
				if origin == app.CORSTrustedOrigins[i] {
					w.Header().Set("Access-Control-Allow-Origin", origin)
					if r.Method == http.MethodOptions && r.Header.Get("Access-Control-Request-Method") != "" {
						w.Header().Set("Access-Control-Allow-Methods", "OPTIONS, PUT, PATCH, DELETE")
						w.Header().Set("Access-Control-Allow-Headers", "Authorization, Content-Type")
						w.WriteHeader(http.StatusOK)
						return
					}
				}
			}
		}
		next.ServeHTTP(w, r)
	})
}
