package firewall

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

	"github.com/qdm12/gluetun/internal/firewall/iptables"
	"github.com/qdm12/gluetun/internal/firewall/nftables"
	"github.com/qdm12/gluetun/internal/models"
	"github.com/qdm12/gluetun/internal/routing"
)

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

	// Fixed
	impl            firewallImpl
	customRulesPath string

	// State
	enabled           bool
	restore           func(context.Context)
	vpnConnection     models.Connection
	vpnIntf           string
	outboundSubnets   []netip.Prefix
	allowedInputPorts map[uint16]map[string]struct{} // port to interfaces set mapping
	portRedirections  portRedirections
	stateMutex        sync.Mutex
}

// NewConfig creates a new Config instance and returns an error
// if no firewall implementation is available.
func NewConfig(ctx context.Context, implementation string, logger Logger,
	runner CmdRunner, defaultRoutes []routing.DefaultRoute,
	localNetworks []routing.LocalNetwork,
) (config *Config, err error) {
	var impl firewallImpl
	var customRulesPath string
	// TODO after v3.42 release, use nftables if [nftables.IsSupported] is true.
	switch implementation {
	case "auto", "iptables":
		impl, err = iptables.New(ctx, runner, logger)
		if err != nil {
			return nil, fmt.Errorf("creating iptables firewall: %w", err)
		}
		customRulesPath = "/iptables/post-rules.txt"
	case "nftables":
		impl = nftables.New(logger)
		customRulesPath = "/gluetun/firewall/nftables/post-rules.txt"
	default:
		return nil, fmt.Errorf("unknown firewall implementation: %s", implementation)
	}

	return &Config{
		runner:            runner,
		logger:            logger,
		allowedInputPorts: make(map[uint16]map[string]struct{}),
		// Obtained from routing
		defaultRoutes:   defaultRoutes,
		localNetworks:   localNetworks,
		impl:            impl,
		customRulesPath: customRulesPath,
	}, nil
}
