package net

import (
	"errors"
	"fmt"
	"net/netip"
	"slices"
	"time"

	"git.frostfs.info/TrueCloudLab/frostfs-node/internal/metrics"
	"git.frostfs.info/TrueCloudLab/multinet"
)

var errEmptySourceIPList = errors.New("empty source IP list")

type Subnet struct {
	Prefix    string
	SourceIPs []string
}

type Config struct {
	Enabled       bool
	Subnets       []Subnet
	Balancer      string
	Restrict      bool
	FallbackDelay time.Duration
	Metrics       metrics.MultinetMetrics
}

func (c Config) toMultinetConfig() (multinet.Config, error) {
	var subnets []multinet.Subnet
	for _, s := range c.Subnets {
		var ms multinet.Subnet
		p, err := netip.ParsePrefix(s.Prefix)
		if err != nil {
			return multinet.Config{}, fmt.Errorf("parse IP prefix '%s': %w", s.Prefix, err)
		}
		ms.Prefix = p
		for _, ip := range s.SourceIPs {
			addr, err := netip.ParseAddr(ip)
			if err != nil {
				return multinet.Config{}, fmt.Errorf("parse IP address '%s': %w", ip, err)
			}
			ms.SourceIPs = append(ms.SourceIPs, addr)
		}
		if len(ms.SourceIPs) == 0 {
			return multinet.Config{}, errEmptySourceIPList
		}
		subnets = append(subnets, ms)
	}
	return multinet.Config{
		Subnets:       subnets,
		Balancer:      multinet.BalancerType(c.Balancer),
		Restrict:      c.Restrict,
		FallbackDelay: c.FallbackDelay,
		Dialer:        newDefaulDialer(),
		EventHandler:  newEventHandler(c.Metrics),
	}, nil
}

func (c Config) equals(other Config) bool {
	return c.Enabled == other.Enabled &&
		slices.EqualFunc(c.Subnets, other.Subnets, func(lhs, rhs Subnet) bool {
			return lhs.Prefix == rhs.Prefix && slices.Equal(lhs.SourceIPs, rhs.SourceIPs)
		}) &&
		c.Balancer == other.Balancer &&
		c.Restrict == other.Restrict &&
		c.FallbackDelay == other.FallbackDelay
}