package handlers

import (
	"net/http"
	"strings"

	"github.com/mixeme/selfpost/internal/health"
	"github.com/mixeme/selfpost/internal/web/auth"
)

func (h *Handlers) HandleStatus(w http.ResponseWriter, r *http.Request) {
	if _, ok := h.requireGlobal(w, r); !ok {
		return
	}
	data := h.statusBody()
	data["Title"] = "SelfPost — status"
	data["User"] = auth.CurrentUser(r)
	data["Active"] = "status"
	data["IsGlobal"] = true
	data["Flash"] = statusFlash(r)
	h.view.Render(w, http.StatusOK, "status", data)
}

func (h *Handlers) HandleStatusFragment(w http.ResponseWriter, r *http.Request) {
	if _, ok := h.requireGlobal(w, r); !ok {
		return
	}
	h.view.RenderFragment(w, http.StatusOK, "status_body", h.statusBody())
}

func (h *Handlers) HandleStatusRecheck(w http.ResponseWriter, r *http.Request) {
	if _, ok := h.requireGlobal(w, r); !ok {
		return
	}
	h.dns.Server(h.cfg.Hostname, true)
	http.Redirect(w, r, "/status?rechecked=1", http.StatusSeeOther)
}

func (h *Handlers) statusBody() map[string]any {
	procs, procErr := health.Processes()
	procStatus := health.StatusUnknown
	if procErr != nil {
		logf("panel: status: supervisorctl: %v", procErr)
	} else {
		for _, p := range procs {
			procStatus = health.Worst(procStatus, p.Status)
		}
	}

	queueText, queueErr := readQueue()
	queueStatus := health.StatusOK
	if queueErr != "" {
		queueStatus = health.StatusWarn
	}

	cert := health.CheckCertificate(h.cfg.TLSCertFile)
	sockets := []health.Socket{
		health.CheckSocket("OpenDKIM", h.cfg.OpenDKIMSocket, true),
		health.CheckSocket("send-log", h.cfg.JournalSocket, false),
	}
	socketStatus := health.StatusUnknown
	for _, sock := range sockets {
		socketStatus = health.Worst(socketStatus, sock.Status)
	}

	machine := h.machine.Sample()
	srv := h.dns.Server(h.cfg.Hostname, false)

	overall := health.Worst(procStatus, queueStatus, cert.Status, socketStatus, machine.Status)
	return map[string]any{
		"Processes":      procs,
		"ProcessError":   procErr != nil,
		"ProcessStatus":  procStatus,
		"QueueSummary":   queueSummary(queueText),
		"QueueError":     queueErr,
		"QueueStatus":    queueStatus,
		"Machine":        machine,
		"Cert":           cert,
		"Sockets":        sockets,
		"SocketStatus":   socketStatus,
		"Hostname":       h.cfg.Hostname,
		"PTR":            srv.PTR,
		"OverallStatus":  overall,
		"OverallHeading": overallHeading(overall),
	}
}

func queueSummary(out string) string {
	lines := strings.Split(strings.TrimSpace(out), "\n")
	for i := len(lines) - 1; i >= 0; i-- {
		if line := strings.TrimSpace(lines[i]); line != "" {
			return strings.TrimSpace(strings.TrimPrefix(line, "--"))
		}
	}
	return ""
}

func overallHeading(worst health.Status) string {
	switch worst {
	case health.StatusError:
		return "A component needs attention — see the details below."
	case health.StatusWarn:
		return "Running, with warnings below."
	case health.StatusOK:
		return "All components are running normally."
	default:
		return "Some checks could not be performed."
	}
}

func statusFlash(r *http.Request) string {
	switch {
	case r.URL.Query().Get("reloaded") != "":
		return "Configuration regenerated from the database; OpenDKIM and Postfix have re-read it."
	case r.URL.Query().Get("rechecked") != "":
		return "DNS re-checked."
	default:
		return ""
	}
}
