package main

import (
	"errors"
	"fmt"
	"net"
	"net/netip"
	"syscall"

	"golang.org/x/net/route"
)

func defaultRouteIP() (netip.Addr, error) {
	idx, err := defaultRouteInterfaceIndex()
	if err != nil {
		return netip.Addr{}, err
	}
	iface, err := net.InterfaceByIndex(idx)
	if err != nil {
		return netip.Addr{}, err
	}
	addrs, err := iface.Addrs()
	if err != nil {
		return netip.Addr{}, err
	}
	for _, addr := range addrs {
		ip := addr.(*net.IPNet).IP
		if ip.To4() != nil {
			return netip.AddrFrom4(*(*[4]byte)(ip)), nil
		}
	}

	return netip.Addr{}, errors.New("no ipv4 addr")
}

func defaultRouteInterfaceIndex() (int, error) {
	rib, err := route.FetchRIB(syscall.AF_UNSPEC, syscall.NET_RT_DUMP2, 0)
	if err != nil {
		return 0, fmt.Errorf("route.FetchRIB: %w", err)
	}
	msgs, err := route.ParseRIB(syscall.NET_RT_IFLIST2, rib)
	if err != nil {
		return 0, fmt.Errorf("route.ParseRIB: %w", err)
	}
	for _, message := range msgs {
		routeMessage := message.(*route.RouteMessage)
		if routeMessage.Flags&(syscall.RTF_UP|syscall.RTF_GATEWAY|syscall.RTF_STATIC) == 0 {
			continue
		}

		addresses := routeMessage.Addrs

		destination, ok := addresses[0].(*route.Inet4Addr)
		if !ok {
			continue
		}

		if destination.IP != [4]byte{0, 0, 0, 0} {
			continue
		}

		switch addresses[1].(type) {
		case *route.Inet4Addr:
			return routeMessage.Index, nil
		default:
			continue
		}
	}

	return 0, fmt.Errorf("ambiguous gateway interfaces found")
}