package store

import (
	"net"
	"net/http"
	"strings"
	"time"
)

// getClientIP extracts the client IP address, checking X-Forwarded-For first
func getClientIP(r *http.Request) string {
	// Check X-Forwarded-For header (comma-separated list, first is client)
	if xff := r.Header.Get("X-Forwarded-For"); xff != "" {
		// Take the first IP in the list
		ips := strings.Split(xff, ",")
		if len(ips) > 0 {
			return strings.TrimSpace(ips[0])
		}
	}

	// Fall back to RemoteAddr (format: "IP:port" or "[IPv6]:port")
	// Use net.SplitHostPort to properly handle both IPv4 and IPv6
	host, _, err := net.SplitHostPort(r.RemoteAddr)
	if err != nil {
		// If SplitHostPort fails, return as-is (shouldn't happen with valid RemoteAddr)
		return r.RemoteAddr
	}
	return host
}

// TrackRedirect increments the redirect counter for this IP+UA+Path combination
// Returns the current attempt count, whether limit was exceeded, and the track details
func (s *Store) TrackRedirect(r *http.Request, path string, maxAttempts int) (attempts int, exceeded bool, track *RedirectTrack) {
	if r == nil {
		return 0, false, nil
	}

	ip := getClientIP(r)
	userAgent := r.UserAgent()
	key := redirectKey(ip, userAgent, path)

	now := time.Now()
	expiresAt := now.Add(5 * time.Minute)

	// Try to load existing track
	val, exists := s.redirectTracks.Load(key)
	if exists {
		track = val.(*RedirectTrack)

		// Check if expired
		if now.After(track.ExpiresAt) {
			// Expired, start fresh
			track = &RedirectTrack{
				IP:        ip,
				UserAgent: userAgent,
				Path:      path,
				Attempts:  1,
				FirstSeen: now,
				ExpiresAt: expiresAt,
			}
			s.redirectTracks.Store(key, track)
			return 1, false, track
		}

		// Increment existing
		track.Attempts++
		track.ExpiresAt = expiresAt // Extend expiry
		exceeded = track.Attempts >= maxAttempts
		return track.Attempts, exceeded, track
	}

	// Create new track
	track = &RedirectTrack{
		IP:        ip,
		UserAgent: userAgent,
		Path:      path,
		Attempts:  1,
		FirstSeen: now,
		ExpiresAt: expiresAt,
	}
	s.redirectTracks.Store(key, track)
	return 1, false, track
}

// ClearRedirectTrack removes a redirect tracking entry (called after successful completion)
func (s *Store) ClearRedirectTrack(r *http.Request, path string) {
	if r == nil {
		return
	}

	ip := getClientIP(r)
	userAgent := r.UserAgent()
	key := redirectKey(ip, userAgent, path)
	s.redirectTracks.Delete(key)
}
