package handlers

import (
	"nano-router/config"
	"nano-router/dhcp"
	"nano-router/network"
	"net/http"
	"strings"
)

func collectAllSubnets(excludeIface string) []network.SubnetOverlap {
	var result []network.SubnetOverlap

	appCfg, _ := config.Load()
	if appCfg != nil {
		for name, ic := range appCfg.Interfaces {
			if name == excludeIface {
				continue
			}
			addr, mask := resolveIfaceIP(name, ic.Mode, ic.Address, ic.Netmask)
			if addr != "" && mask != "" {
				result = append(result, network.SubnetOverlap{
					Interface: name,
					Label:     ic.Label,
					Subnet:    addr + "/" + mask,
				})
			}
		}
	}

	for name, pcfg := range network.GetAllPending() {
		if name == excludeIface {
			continue
		}
		addr, mask := resolveIfaceIP(name, pcfg.Mode, pcfg.Address, pcfg.Netmask)
		if addr != "" && mask != "" {
			result = append(result, network.SubnetOverlap{
				Interface: name,
				Label:     pcfg.Label,
				Subnet:    addr + "/" + mask,
			})
		}
	}

	names, _ := network.GetInterfaces()
	for _, name := range names {
		if name == excludeIface {
			continue
		}
		s, err := network.GetInterfaceStats(name)
		if err != nil || s.IPv4 == "" || s.IPv4Mask == "" {
			continue
		}
		var mode string
		if appCfg != nil && appCfg.Interfaces != nil {
			if ic, ok := appCfg.Interfaces[name]; ok {
				mode = ic.Mode
			}
		}
		if mode == "dhcp" {
			result = append(result, network.SubnetOverlap{
				Interface: name,
				Subnet:    s.IPv4 + "/" + s.IPv4Mask,
			})
		}
	}

	if appCfg != nil {
		for _, pool := range appCfg.DHCP.Pools {
			if pool.Interface == excludeIface {
				continue
			}
			if pool.Subnet != "" && pool.Netmask != "" {
				result = append(result, network.SubnetOverlap{
					Interface: pool.Interface,
					Subnet:    pool.Subnet + "/" + pool.Netmask,
				})
			}
		}
	}

	return result
}

func resolveIfaceIP(name, mode, addr, mask string) (string, string) {
	if mode == "static" && addr != "" && mask != "" {
		return addr, mask
	}
	if mode == "dhcp" {
		s, err := network.GetInterfaceStats(name)
		if err != nil {
			return "", ""
		}
		if s.IPv4 != "" && s.IPv4Mask != "" {
			return s.IPv4, s.IPv4Mask
		}
	}
	return "", ""
}

func collectAllSubnetsForDHCP(excludeIface string) []network.SubnetOverlap {
	result := collectAllSubnets(excludeIface)

	cfg, _ := dhcp.Load()
	if cfg != nil {
		for _, pool := range cfg.Pools {
			if pool.Interface == excludeIface {
				continue
			}
			if pool.Subnet != "" && pool.Netmask != "" {
				result = append(result, network.SubnetOverlap{
					Interface: pool.Interface,
					Subnet:    pool.Subnet + "/" + pool.Netmask,
				})
			}
		}
	}

	return result
}

func checkInterfaceOverlap(cfg *network.InterfaceConfig) (string, bool) {
	if cfg.Mode != "static" || cfg.Address == "" || cfg.Netmask == "" {
		return "", false
	}

	all := collectAllSubnets(cfg.Name)
	overlaps := network.CheckOverlap(cfg.Address, cfg.Netmask, cfg.Name, all)
	if len(overlaps) > 0 {
		var names []string
		for _, o := range overlaps {
			label := o.Interface
			if o.Label != "" {
				label = o.Label + " (" + o.Interface + ")"
			}
			names = append(names, label)
		}
		return "IP-адрес пересекается с подсетью интерфейса " + strings.Join(names, ", "), true
	}
	return "", false
}

func checkDHCPPoolOverlap(subnet, mask, iface string) (string, bool) {
	if subnet == "" || mask == "" {
		return "", false
	}

	all := collectAllSubnetsForDHCP(iface)
	overlaps := network.CheckOverlap(subnet, mask, iface, all)
	if len(overlaps) > 0 {
		var names []string
		for _, o := range overlaps {
			label := o.Interface
			if o.Label != "" {
				label = o.Label + " (" + o.Interface + ")"
			}
			names = append(names, label)
		}
		return "Подсеть пересекается с " + strings.Join(names, ", "), true
	}
	return "", false
}

func HandleSubnets(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodGet {
		fail(w, http.StatusMethodNotAllowed, "method not allowed")
		return
	}
	exclude := r.URL.Query().Get("exclude")
	result := collectAllSubnets(exclude)
	ok(w, result)
}