package platform

import (
	"fmt"
	"net"
	"net/http"
)

// StartLocalAPIServer runs the /api reverse proxy on a loopback HTTP listener and
// returns its base URL (e.g. http://127.0.0.1:54321).
//
// Why: on Windows, Wails' custom-scheme AssetServer buffers a handler's response
// until the handler RETURNS, so a long-lived SSE (/api/hub/events, whose handler
// never returns) never reaches the WebView — the device list never loads and the
// status sticks on "connecting". A real loopback HTTP origin is served by
// WebView2's normal network stack, which streams response bodies incrementally.
//
// The page reaches this via the injected api_base; since its origin differs from
// the listener, CORS is added. No credentials/cookies are used (auth is a Bearer
// header), so a permissive policy is safe. macOS (WKWebView) streams the custom
// scheme fine and doesn't use this.
func StartLocalAPIServer(apiBase string) (string, error) {
	proxy, err := NewAPIProxy(apiBase)
	if err != nil {
		return "", err
	}
	ln, err := net.Listen("tcp", "127.0.0.1:0")
	if err != nil {
		return "", fmt.Errorf("local api: listen: %w", err)
	}
	srv := &http.Server{Handler: corsWrap(proxy)}
	go func() { _ = srv.Serve(ln) }()
	return "http://" + ln.Addr().String(), nil
}

// corsWrap adds permissive CORS so the WebView page (a different origin than this
// loopback listener) can fetch /api, and answers the preflight. Includes the
// Private Network Access ack since the page origin is also loopback.
func corsWrap(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		origin := r.Header.Get("Origin")
		if origin == "" {
			origin = "*"
		}
		h := w.Header()
		h.Set("Access-Control-Allow-Origin", origin)
		h.Add("Vary", "Origin")
		h.Add("Vary", "Access-Control-Request-Headers")
		h.Set("Access-Control-Allow-Methods", "GET, POST, PUT, PATCH, DELETE, OPTIONS")
		// Echo the requested headers so every client header is allowed without
		// maintaining a list — the app sends Authorization, X-Device-Name,
		// X-Device-Type, and conditional headers like If-None-Match (clipboard
		// caching). Missing one fails the preflight as a "Failed to fetch".
		if reqHeaders := r.Header.Get("Access-Control-Request-Headers"); reqHeaders != "" {
			h.Set("Access-Control-Allow-Headers", reqHeaders)
		} else {
			h.Set("Access-Control-Allow-Headers",
				"Authorization, Content-Type, X-Device-Name, X-Device-Type, X-Dev-User, If-None-Match")
		}
		h.Set("Access-Control-Allow-Private-Network", "true")
		h.Set("Access-Control-Max-Age", "600")
		if r.Method == http.MethodOptions {
			w.WriteHeader(http.StatusNoContent)
			return
		}
		next.ServeHTTP(w, r)
	})
}
