// Package geocounter exposes the gin middleware that records
// `(user_id, country)` counters for every authenticated user-surface
// request. The middleware sits one layer below `userid.Middleware` in
// the route chain: it relies on the parsed user id already being on
// the request context.
//
// The middleware never blocks: the underlying counter implementation
// looks up the country synchronously (mmap read) and dispatches the
// database upsert to a fire-and-forget goroutine. Errors from the
// asynchronous path are logged inside the geo service, never surfaced
// to the response.
package geocounter

import (
	"context"

	"galaxy/backend/internal/server/clientip"
	"galaxy/backend/internal/server/middleware/userid"

	"github.com/gin-gonic/gin"
	"github.com/google/uuid"
)

// Service is the narrow contract the middleware needs from the geo
// package. It is satisfied by `*geo.Service` directly; tests inject a
// recording stub. A nil Service is allowed and disables the
// middleware's side effect.
type Service interface {
	IncrementCounterAsync(ctx context.Context, userID uuid.UUID, sourceIP string)
}

// Middleware returns a gin handler that, after the wrapped handler
// chain has run, dispatches an `IncrementCounterAsync` call for the
// authenticated user and the originating IP. svc may be nil, in which
// case the middleware is a no-op pass-through.
//
// The middleware reads the user id from the request context populated
// by `userid.Middleware`; routes that mount this middleware without
// `userid.Middleware` ahead of it will silently skip the increment
// because the user id is absent.
func Middleware(svc Service) gin.HandlerFunc {
	return func(c *gin.Context) {
		c.Next()

		if svc == nil {
			return
		}
		userID, ok := userid.FromContext(c.Request.Context())
		if !ok || userID == uuid.Nil {
			return
		}
		ip := clientip.ExtractSourceIP(c)
		if ip == "" {
			return
		}
		svc.IncrementCounterAsync(c.Request.Context(), userID, ip)
	}
}
