package webui

import (
	"net"
	"net/http"

	"mailgoserver/internal/db"
)

func (a *App) ipsList(w http.ResponseWriter, r *http.Request) {
	ips, err := a.DB.ListWhitelistedIPs()
	if err != nil {
		setFlash(w, "error", "Error loading IP whitelist")
	}
	scope := scopeFromContext(r)
	var pairs [][2]any
	for _, ip := range ips {
		if !scope.Allowed(ip.DomainID) {
			continue
		}
		pairs = append(pairs, [2]any{ip.WhitelistedIP, M{"domain_name": ip.DomainName}})
	}
	a.render(w, r, "ips.html", M{"active": "ips", "ips": pairs})
}

func (a *App) addIPForm(w http.ResponseWriter, r *http.Request) {
	domains, _ := a.accessibleDomains(r)
	a.render(w, r, "add_ip.html", M{"active": "ips", "domains": domains, "prefill_ip": r.URL.Query().Get("ip")})
}

// addIP mirrors ip_whitelist.py's add_ip() POST branch: IPv4-only validation via
// net.ParseIP + To4(), matching Python's socket.inet_aton behavior (CIDR is rejected
// here despite edit_ip.html's placeholder implying CIDR support — that mismatch is
// preserved from the Python version).
func (a *App) addIP(w http.ResponseWriter, r *http.Request) {
	ip := r.FormValue("ip_address")
	domainID := int64(atoi(r.FormValue("domain_id")))
	storeMessage := r.FormValue("store_message_content") == "on"

	if net.ParseIP(ip).To4() == nil || domainID == 0 {
		setFlash(w, "error", "A valid IPv4 address and domain are required")
		http.Redirect(w, r, Prefix+"/ips/add", http.StatusFound)
		return
	}
	if !requireDomainAccess(w, r, domainID) {
		return
	}
	if exists, _ := a.DB.IPPairExists(ip, domainID, -1); exists {
		setFlash(w, "error", "This IP is already whitelisted for this domain")
		http.Redirect(w, r, Prefix+"/ips/add", http.StatusFound)
		return
	}
	if _, err := a.DB.CreateWhitelistedIP(ip, domainID, storeMessage); err != nil {
		setFlash(w, "error", "Error adding IP")
		http.Redirect(w, r, Prefix+"/ips/add", http.StatusFound)
		return
	}
	setFlash(w, "success", "IP address whitelisted successfully")
	http.Redirect(w, r, Prefix+"/ips", http.StatusFound)
}

// ipWithAccess fetches a whitelisted-IP row by path ID and confirms it belongs to a
// domain the current admin can manage.
func (a *App) ipWithAccess(w http.ResponseWriter, r *http.Request) (rec *db.WhitelistedIP, ok bool) {
	rec, err := a.DB.GetWhitelistedIPByID(pathID(r))
	if err != nil || rec == nil {
		http.NotFound(w, r)
		return nil, false
	}
	if !requireDomainAccess(w, r, rec.DomainID) {
		return nil, false
	}
	return rec, true
}

func (a *App) disableIP(w http.ResponseWriter, r *http.Request) {
	rec, ok := a.ipWithAccess(w, r)
	if !ok {
		return
	}
	if err := a.DB.SetWhitelistedIPActive(rec.ID, false); err != nil {
		setFlash(w, "error", "Error disabling IP")
	} else {
		setFlash(w, "success", "IP disabled")
	}
	http.Redirect(w, r, Prefix+"/ips", http.StatusFound)
}

func (a *App) enableIP(w http.ResponseWriter, r *http.Request) {
	rec, ok := a.ipWithAccess(w, r)
	if !ok {
		return
	}
	if err := a.DB.SetWhitelistedIPActive(rec.ID, true); err != nil {
		setFlash(w, "error", "Error enabling IP")
	} else {
		setFlash(w, "success", "IP enabled")
	}
	http.Redirect(w, r, Prefix+"/ips", http.StatusFound)
}

func (a *App) removeIP(w http.ResponseWriter, r *http.Request) {
	rec, ok := a.ipWithAccess(w, r)
	if !ok {
		return
	}
	if err := a.DB.RemoveWhitelistedIP(rec.ID); err != nil {
		setFlash(w, "error", "Error removing IP")
	} else {
		setFlash(w, "success", "IP permanently removed")
	}
	http.Redirect(w, r, Prefix+"/ips", http.StatusFound)
}

func (a *App) editIPForm(w http.ResponseWriter, r *http.Request) {
	rec, ok := a.ipWithAccess(w, r)
	if !ok {
		return
	}
	domains, _ := a.accessibleDomains(r)
	a.render(w, r, "edit_ip.html", M{"active": "ips", "ip_record": rec, "domains": domains})
}

// editIP mirrors ip_whitelist.py's edit_ip() POST branch.
func (a *App) editIP(w http.ResponseWriter, r *http.Request) {
	rec, ok := a.ipWithAccess(w, r)
	if !ok {
		return
	}
	id := rec.ID
	domains, _ := a.accessibleDomains(r)

	ip := r.FormValue("ip_address")
	domainID := int64(atoi(r.FormValue("domain_id")))
	storeMessage := r.FormValue("store_message_content") == "on"

	if net.ParseIP(ip).To4() == nil || domainID == 0 {
		setFlash(w, "error", "A valid IPv4 address and domain are required")
		a.render(w, r, "edit_ip.html", M{"active": "ips", "ip_record": rec, "domains": domains})
		return
	}
	if !requireDomainAccess(w, r, domainID) {
		return
	}
	if exists, _ := a.DB.IPPairExists(ip, domainID, id); exists {
		setFlash(w, "error", "This IP is already whitelisted for this domain")
		a.render(w, r, "edit_ip.html", M{"active": "ips", "ip_record": rec, "domains": domains})
		return
	}
	if err := a.DB.UpdateWhitelistedIP(id, ip, domainID, storeMessage); err != nil {
		setFlash(w, "error", "Error updating IP")
		http.Redirect(w, r, Prefix+"/ips", http.StatusFound)
		return
	}
	setFlash(w, "success", "IP whitelist entry updated successfully")
	http.Redirect(w, r, Prefix+"/ips", http.StatusFound)
}
