package apiv1

import (
	"context"
	"errors"
	"net/http"

	"git.ar21.de/yolokube/country-geo-locations/internal/cache"
	"git.ar21.de/yolokube/country-geo-locations/internal/database"
	"git.ar21.de/yolokube/country-geo-locations/pkg/geoloc"
	"github.com/go-chi/chi/v5"
)

type LocationHandler struct {
	cache *cache.Cache
	db    *database.Database
}

func NewLocationHandler(cache *cache.Cache, db *database.Database) *LocationHandler {
	return &LocationHandler{
		cache: cache,
		db:    db,
	}
}

func (lh *LocationHandler) SearchIPHandlerFunc(w http.ResponseWriter, r *http.Request) {
	ipinfo, ok := r.Context().Value(keyIPInfo).(*geoloc.IPInfo)
	if !ok {
		renderResponse(w, r, errRender(errors.New("could not get ipinfo object")))
		return
	}

	renderResponse(w, r, newIPInfoResponse(ipinfo))
}

func (lh *LocationHandler) SearchIPHandler(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		var ipinfo *geoloc.IPInfo

		if ipAddress := chi.URLParam(r, "ipAddress"); ipAddress != "" {
			ipnetnum, err := geoloc.CalculateIPNum(ipAddress)
			if err != nil {
				renderResponse(w, r, errInvalidRequest(err))
				return
			}

			newipnet, found := lh.cache.Get(ipnetnum)
			if found {
				ipnetnum = newipnet
			}

			ipinfo, err = lh.db.SearchIPNet(ipnetnum)
			if err != nil {
				renderResponse(w, r, errNotFound())
				return
			}

			if !found {
				lh.cache.Set(ipnetnum, ipinfo.IPNumFrom)
			}
		}
		ctx := context.WithValue(r.Context(), keyIPInfo, ipinfo)
		next.ServeHTTP(w, r.WithContext(ctx))
	})
}