package iptools

import (
	"fmt"
	"net/netip"
	"sort"
	"strings"
	"time"
)

type LeaseInfo struct {
	HostName        string          `yaml:"hostname"`
	Addr            netip.Addr      `yaml:"addr"`
	HardwareAddress HardwareAddress `yaml:"mac_addr"`
	Expires         time.Time       `yaml:"expires"`
}

type sortableLease []*LeaseInfo

func (a sortableLease) Len() int           { return len(a) }
func (a sortableLease) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a sortableLease) Less(i, j int) bool { return a[i].Addr.Less(a[j].Addr) }

func (li *LeaseInfo) ResetExpiry(t time.Time, dur time.Duration) {
	li.Expires = t.Add(dur)
}

func (li *LeaseInfo) IsExpired(t time.Time) bool {
	return t.After(li.Expires)
}

func (li *LeaseInfo) Expire() {
	li.Expires = time.Time{}
}

func SortLeases(leases []*LeaseInfo) []*LeaseInfo {
	sortable := sortableLease(leases)
	sort.Sort(sortable)

	return []*LeaseInfo(sortable)
}

func (lease *LeaseInfo) Reset() *LeaseInfo {
	lease.Expires = time.Time{}
	lease.HardwareAddress = nil
	return lease
}

func (lease LeaseInfo) Compare(other LeaseInfo) error {
	susFields := []string{}

	if lease.Addr != other.Addr {
		susFields = append(susFields, fmt.Sprintf("address is %s, but is recorded as %s", lease.Addr, other.Addr))
	}

	if !lease.HardwareAddress.Match(other.HardwareAddress) {
		susFields = append(susFields, fmt.Sprintf("hardware address is %s, but is recorded as %s", lease.HardwareAddress, other.HardwareAddress))
	}

	if lease.HostName != other.HostName {
		susFields = append(susFields, fmt.Sprintf("hostname is %s, but is recorded as %s", lease.HostName, other.HostName))
	}

	if len(susFields) > 0 {
		return fmt.Errorf("suspicious lease: %s", strings.Join(susFields, ";"))
	}

	return nil
}