package daemon

import (
	"errors"
	"fmt"
	"log/slog"
	"net"
	"net/http"
	"net/http/pprof"
	"strings"
	"time"
)

// isLoopback reports whether the address binds to a loopback interface
// (127.0.0.1, ::1, localhost). REQ-123: pprof must be loopback-only.
//
// An empty host (e.g. ":6060") binds ALL interfaces and is therefore
// treated as NON-loopback (F2: loopback-bypass fix). Only an explicit
// loopback IP or the "localhost" name is accepted.
func isLoopback(addr string) bool {
	host, _, err := net.SplitHostPort(addr)
	if err != nil {
		host = addr
	}
	host = strings.TrimSpace(host)
	// F2: empty host (":6060") binds all interfaces — reject.
	if host == "" {
		return false
	}
	if host == "localhost" {
		return true
	}
	ip := net.ParseIP(host)
	if ip != nil {
		return ip.IsLoopback()
	}
	return false
}

// StartPprof starts the pprof HTTP server on addr. REQ-123: pprof is
// unauthenticated and MUST bind to a loopback interface only; this is a
// hard invariant (F2: the --pprof-allow-public override was a phantom flag
// that was never implemented and has been removed — non-loopback binds are
// always refused).
func StartPprof(addr string, log *slog.Logger) (*http.Server, error) {
	if addr == "" {
		return nil, nil
	}
	// REQ-123: pprof must bind to loopback only. This is a hard
	// invariant; there is no public-bind override.
	if !isLoopback(addr) {
		log.Error("pprof refuses non-loopback bind",
			slog.String("addr", addr),
			slog.String("reason", "REQ-123: pprof is unauthenticated; loopback-only is a hard invariant"))
		return nil, fmt.Errorf("pprof: refusing non-loopback bind %s (REQ-123; unauthenticated; loopback-only is a hard invariant)", addr)
	}
	mux := http.NewServeMux()
	mux.HandleFunc("/debug/pprof/", pprof.Index)
	mux.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline)
	mux.HandleFunc("/debug/pprof/profile", pprof.Profile)
	mux.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
	mux.HandleFunc("/debug/pprof/trace", pprof.Trace)
	mux.Handle("/debug/pprof/heap", pprof.Handler("heap"))
	mux.Handle("/debug/pprof/goroutine", pprof.Handler("goroutine"))
	mux.Handle("/debug/pprof/threadcreate", pprof.Handler("threadcreate"))
	mux.Handle("/debug/pprof/block", pprof.Handler("block"))
	mux.Handle("/debug/pprof/mutex", pprof.Handler("mutex"))

	server := &http.Server{
		Addr:              addr,
		Handler:           mux,
		ReadHeaderTimeout: 5 * time.Second,
	}

	log.Warn("pprof endpoint exposed",
		slog.String("addr", addr),
		slog.String("warning", "unauthenticated, operator-only — do not expose publicly"))

	go func() {
		err := server.ListenAndServe()
		if err != nil && !errors.Is(err, http.ErrServerClosed) {
			log.Error("pprof server stopped", slog.String("addr", addr), slog.Any("err", err))
		}
	}()

	return server, nil
}
