package handlers

import (
	"encoding/json"
	"log"
	"net/http"
	"strings"

	"alpine-router/clients"
	"alpine-router/config"
	"alpine-router/dhcp"
)

func HandleClients(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodGet {
		fail(w, http.StatusMethodNotAllowed, "method not allowed")
		return
	}

	list, err := clients.GetAll()
	if err != nil {
		fail(w, http.StatusInternalServerError, err.Error())
		return
	}

	ok(w, list)
}

func HandleClientUpdate(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodPost {
		fail(w, http.StatusMethodNotAllowed, "method not allowed")
		return
	}

	mac := strings.TrimPrefix(r.URL.Path, "/api/clients/update/")
	if mac == "" {
		fail(w, http.StatusBadRequest, "mac address required")
		return
	}

	var req struct {
		Hostname string `json:"hostname"`
		Blocked  bool   `json:"blocked"`
		StaticIP string `json:"static_ip"`
	}
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		fail(w, http.StatusBadRequest, "invalid json: "+err.Error())
		return
	}

	if err := updateClient(mac, req.Hostname, req.Blocked, req.StaticIP); err != nil {
		fail(w, http.StatusInternalServerError, err.Error())
		return
	}

	go applyBlockedFirewall()
	go applyDHCPStaticBindings()
	ok(w, map[string]string{"message": "updated"})
}

func updateClient(mac, hostname string, blocked bool, staticIP string) error {
	cfg, err := config.Load()
	if err != nil {
		return err
	}

	found := false
	for i := range cfg.KnownDevices {
		if cfg.KnownDevices[i].MAC == mac {
			cfg.KnownDevices[i].Blocked = blocked
			cfg.KnownDevices[i].Hostname = hostname
			cfg.KnownDevices[i].StaticIP = staticIP
			found = true
			break
		}
	}

	if !found {
		cfg.KnownDevices = append(cfg.KnownDevices, config.KnownDevice{
			MAC:      mac,
			Hostname: hostname,
			Blocked:  blocked,
			StaticIP: staticIP,
		})
	}

	return config.Save(cfg)
}


func applyDHCPStaticBindings() {
	if !dhcp.IsInstalled() {
		return
	}

	cfg, err := config.Load()
	if err != nil {
		log.Printf("Warning: load config for DHCP static bindings: %v", err)
		return
	}

	var bindings []dhcp.StaticBinding
	for _, kd := range cfg.KnownDevices {
		if kd.StaticIP != "" && kd.MAC != "" {
			bindings = append(bindings, dhcp.StaticBinding{
				MAC:  kd.MAC,
				Host: kd.Hostname,
				IP:   kd.StaticIP,
			})
		}
	}

	dhcpCfg := &dhcp.Config{
		Enabled: cfg.DHCP.Enabled,
		Pools:   make([]dhcp.Pool, len(cfg.DHCP.Pools)),
	}
	for i, p := range cfg.DHCP.Pools {
		dhcpCfg.Pools[i] = dhcp.Pool{
			Interface:  p.Interface,
			Enabled:    p.Enabled,
			Subnet:     p.Subnet,
			Netmask:    p.Netmask,
			RangeStart: p.RangeStart,
			RangeEnd:   p.RangeEnd,
			Router:     p.Router,
			DNS:        p.DNS,
			LeaseTime:  p.LeaseTime,
		}
	}

	if err := dhcp.WriteConfigsWithBindings(dhcpCfg, bindings); err != nil {
		log.Printf("Warning: write dnsmasq config with static bindings: %v", err)
		return
	}

	if dhcpCfg.Enabled {
		if err := dhcp.ServiceRestart(); err != nil {
			log.Printf("Warning: restart dnsmasq after static binding update: %v", err)
		} else {
			log.Printf("dnsmasq restarted with %d static bindings", len(bindings))
		}
	}
}
