package handlers

import (
	"sort"
	"strings"
	"time"

	"nano-router/clients"
	"nano-router/config"
)

// StartPolicySync starts a background goroutine that re-applies nftables rules
// whenever the ARP table changes for devices that have an explicit policy.
// This ensures that policy (VPN / disabled) follows a device even when its IP
// changes due to DHCP renewal or it connects on a different interface.
func StartPolicySync(interval time.Duration) {
	go func() {
		// Give the binary time to fully start before the first check.
		time.Sleep(15 * time.Second)
		var lastSig string
		for {
			sig := policyARPSignature()
			if sig != lastSig {
				lastSig = sig
				applyBlockedFirewall()
			}
			time.Sleep(interval)
		}
	}()
}

// policyARPSignature returns a stable string that captures the current mapping
// of MAC→IPs only for devices that have an explicit (non-default) policy.
// If the string changes between ticks, the firewall needs to be re-applied.
func policyARPSignature() string {
	cfg, err := config.Load()
	if err != nil {
		return ""
	}

	// Collect MACs with explicit policies.
	policyMACs := make(map[string]string) // mac → policy
	for _, kd := range cfg.KnownDevices {
		if kd.MAC != "" && kd.Policy != "" {
			policyMACs[kd.MAC] = kd.Policy
		}
		// Also treat legacy blocked=true as disabled policy.
		if kd.MAC != "" && kd.Blocked && kd.Policy == "" {
			policyMACs[kd.MAC] = "disabled"
		}
	}

	if len(policyMACs) == 0 {
		return ""
	}

	arpByMAC := clients.GetARPIPsByMAC()

	var parts []string
	for mac, policy := range policyMACs {
		ips := arpByMAC[mac]
		sort.Strings(ips)
		parts = append(parts, policy+":"+mac+"="+strings.Join(ips, ","))
	}
	sort.Strings(parts)
	return strings.Join(parts, "|")
}
