package main

import (
	"log"
	"net"
	"os"
	"os/signal"
	"syscall"

	"git.krilio.net/nuno/wgctl-conntrack/cmd"
	"git.krilio.net/nuno/wgctl-conntrack/config"
	ctconn "git.krilio.net/nuno/wgctl-conntrack/conntrack"
	"git.krilio.net/nuno/wgctl-conntrack/resolver"
	"git.krilio.net/nuno/wgctl-conntrack/writer"
)

func main() {
	flags := cmd.Parse()

	cfg, err := config.Load(flags.WGDir)
	if err != nil {
		log.Fatalf("failed to load config: %v", err)
	}
	if flags.Subnet != "" {
		cfg.WGSubnet = flags.Subnet
	}
	if flags.LogFile != "" {
		cfg.AcceptLogFile = flags.LogFile
	}

	_, wgSubnet, err := net.ParseCIDR(cfg.WGSubnet)
	if err != nil {
		log.Fatalf("invalid WG subnet %q: %v", cfg.WGSubnet, err)
	}

	log.Printf("wgctl-conntrack v%s starting (subnet: %s, log: %s)",
		cmd.Version, cfg.WGSubnet, cfg.AcceptLogFile)

	peerResolver := resolver.NewPeerResolver(flags.WGDir)
	svcResolver := resolver.NewServiceResolver(cfg.ServicesFile)

	res := &combinedResolver{peers: peerResolver, services: svcResolver}
	events := make(chan ctconn.TrafficEvent, 512)

	go writer.NewLogWriter(cfg.AcceptLogFile).Run(events)

	sub := ctconn.NewSubscriber(wgSubnet, events, res)
	go func() {
		if err := sub.Run(); err != nil {
			log.Fatalf("conntrack subscriber error: %v", err)
		}
	}()

	sig := make(chan os.Signal, 1)
	signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM)
	<-sig
	log.Println("wgctl-conntrack shutting down")
}

type combinedResolver struct {
	peers    *resolver.PeerResolver
	services *resolver.ServiceResolver
}

func (r *combinedResolver) PeerForIP(ip net.IP) string {
	return r.peers.PeerForIP(ip)
}

func (r *combinedResolver) ServiceForDst(ip net.IP, port uint16, proto string) string {
	return r.services.ServiceForDst(ip, port, proto)
}