// Package ipfilter provides IP address and CIDR range matching for ja4-platform services.
package ipfilter

import (
	"fmt"
	"net"
	"sync"
)

// Filter checks if an IP address should be excluded based on a list of IPs or CIDR ranges
type Filter struct {
	mu      sync.RWMutex
	networks []*net.IPNet
	ips      []net.IP
}

// New creates a new IP filter from a list of IP addresses or CIDR ranges
// Accepts formats like: "192.168.1.1", "10.0.0.0/8", "2001:db8::/32"
func New(excludeList []string) (*Filter, error) {
	f := &Filter{
		networks: make([]*net.IPNet, 0),
		ips:      make([]net.IP, 0),
	}

	for _, entry := range excludeList {
		if entry == "" {
			continue
		}

		// Try parsing as CIDR first
		if _, ipNet, err := net.ParseCIDR(entry); err == nil {
			f.networks = append(f.networks, ipNet)
			continue
		}

		// Try parsing as single IP
		if ip := net.ParseIP(entry); ip != nil {
			f.ips = append(f.ips, ip)
			continue
		}

		return nil, fmt.Errorf("invalid IP or CIDR: %s", entry)
	}

	return f, nil
}

// ShouldExclude checks if an IP address should be excluded
func (f *Filter) ShouldExclude(ipStr string) bool {
	if f == nil {
		return false
	}

	ip := net.ParseIP(ipStr)
	if ip == nil {
		return false
	}

	f.mu.RLock()
	defer f.mu.RUnlock()

	// Check against single IPs
	for _, filterIP := range f.ips {
		if ip.Equal(filterIP) {
			return true
		}
	}

	// Check against CIDR ranges
	for _, network := range f.networks {
		if network.Contains(ip) {
			return true
		}
	}

	return false
}

// Count returns the number of loaded filter entries
func (f *Filter) Count() (ips int, networks int) {
	f.mu.RLock()
	defer f.mu.RUnlock()
	return len(f.ips), len(f.networks)
}
