package firewall

import (
	"context"
	"net/netip"
	"sync"

	"github.com/qdm12/gluetun/internal/models"
	"github.com/qdm12/gluetun/internal/routing"
)

type Config struct {
	runner         CmdRunner
	logger         Logger
	iptablesMutex  sync.Mutex
	ip6tablesMutex sync.Mutex
	defaultRoutes  []routing.DefaultRoute
	localNetworks  []routing.LocalNetwork

	// Fixed state
	ipTables        string
	ip6Tables       string
	customRulesPath string

	// State
	enabled           bool
	vpnConnection     models.Connection
	vpnIntf           string
	outboundSubnets   []netip.Prefix
	allowedInputPorts map[uint16]map[string]struct{} // port to interfaces set mapping
	portRedirections  portRedirections
	outputAddrPort    map[uint16]netip.Addr
	stateMutex        sync.Mutex
}

// NewConfig creates a new Config instance and returns an error
// if no iptables implementation is available.
func NewConfig(ctx context.Context, logger Logger,
	runner CmdRunner, defaultRoutes []routing.DefaultRoute,
	localNetworks []routing.LocalNetwork,
) (config *Config, err error) {
	iptables, err := checkIptablesSupport(ctx, runner, "iptables", "iptables-nft", "iptables-legacy")
	if err != nil {
		return nil, err
	}

	ip6tables, err := findIP6tablesSupported(ctx, runner)
	if err != nil {
		return nil, err
	}

	return &Config{
		runner:            runner,
		logger:            logger,
		allowedInputPorts: make(map[uint16]map[string]struct{}),
		outputAddrPort:    make(map[uint16]netip.Addr),
		ipTables:          iptables,
		ip6Tables:         ip6tables,
		customRulesPath:   "/iptables/post-rules.txt",
		// Obtained from routing
		defaultRoutes: defaultRoutes,
		localNetworks: localNetworks,
	}, nil
}
