package agent

import (
	"net/http"
	"sync"
	"time"

	"github.com/go-chi/chi/v5"

	"github.com/coder/coder/v2/coderd/httpapi"
	"github.com/coder/coder/v2/codersdk"
)

func (a *agent) apiHandler() http.Handler {
	r := chi.NewRouter()
	r.Get("/", func(rw http.ResponseWriter, r *http.Request) {
		httpapi.Write(r.Context(), rw, http.StatusOK, codersdk.Response{
			Message: "Hello from the agent!",
		})
	})

	// Make a copy to ensure the map is not modified after the handler is
	// created.
	cpy := make(map[int]string)
	for k, b := range a.ignorePorts {
		cpy[k] = b
	}

	cacheDuration := 1 * time.Second
	if a.portCacheDuration > 0 {
		cacheDuration = a.portCacheDuration
	}

	lp := &listeningPortsHandler{
		ignorePorts:   cpy,
		cacheDuration: cacheDuration,
	}
	promHandler := PrometheusMetricsHandler(a.prometheusRegistry, a.logger)
	r.Get("/api/v0/listening-ports", lp.handler)
	r.Get("/debug/logs", a.HandleHTTPDebugLogs)
	r.Get("/debug/magicsock", a.HandleHTTPDebugMagicsock)
	r.Get("/debug/magicsock/debug-logging/{state}", a.HandleHTTPMagicsockDebugLoggingState)
	r.Get("/debug/manifest", a.HandleHTTPDebugManifest)
	r.Get("/debug/prometheus", promHandler.ServeHTTP)

	return r
}

type listeningPortsHandler struct {
	ignorePorts   map[int]string
	cacheDuration time.Duration

	//nolint: unused  // used on some but not all platforms
	mut sync.Mutex
	//nolint: unused  // used on some but not all platforms
	ports []codersdk.WorkspaceAgentListeningPort
	//nolint: unused  // used on some but not all platforms
	mtime time.Time
}

// handler returns a list of listening ports. This is tested by coderd's
// TestWorkspaceAgentListeningPorts test.
func (lp *listeningPortsHandler) handler(rw http.ResponseWriter, r *http.Request) {
	ports, err := lp.getListeningPorts()
	if err != nil {
		httpapi.Write(r.Context(), rw, http.StatusInternalServerError, codersdk.Response{
			Message: "Could not scan for listening ports.",
			Detail:  err.Error(),
		})
		return
	}

	httpapi.Write(r.Context(), rw, http.StatusOK, codersdk.WorkspaceAgentListeningPortsResponse{
		Ports: ports,
	})
}
