package processhttp

import (
	"net/http"
	"strings"
)

// IsUpgradeRequest reports whether a request asks the HTTP owner to transfer
// the connection lifecycle to a hijacked protocol. Process and Gateway
// lifecycle deliberately own only complete request/response exchanges.
func IsUpgradeRequest(request *http.Request) bool {
	if request == nil {
		return false
	}
	if strings.TrimSpace(request.Header.Get("Upgrade")) != "" {
		return true
	}
	for _, value := range request.Header.Values("Connection") {
		for _, token := range strings.Split(value, ",") {
			if strings.EqualFold(strings.TrimSpace(token), "upgrade") {
				return true
			}
		}
	}
	return false
}

// WithoutHijacker hides http.Hijacker from the injected handler without
// deciding how an owning transport surface projects upgrade errors. This is
// useful when that owner, such as Gateway, must preserve its own response
// grammar and security headers.
func WithoutHijacker(next http.Handler) http.Handler {
	return http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
		next.ServeHTTP(requestResponseWriter{ResponseWriter: writer}, request)
	})
}

// RequestResponseOnly rejects protocol upgrades and hides http.Hijacker from
// the injected handler. That makes http.Server.Shutdown the owner of every
// transport lifecycle admitted through this wrapper.
func RequestResponseOnly(next http.Handler) http.Handler {
	withoutHijacker := WithoutHijacker(next)
	return http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
		if IsUpgradeRequest(request) {
			writer.Header().Set("Connection", "close")
			http.Error(writer, "upgraded connections are not supported", http.StatusBadRequest)
			return
		}
		withoutHijacker.ServeHTTP(writer, request)
	})
}

// requestResponseWriter intentionally does not expose http.Hijacker or an
// Unwrap method. Flush remains available for bounded streaming responses.
type requestResponseWriter struct{ http.ResponseWriter }

func (writer requestResponseWriter) Flush() {
	if flusher, ok := writer.ResponseWriter.(http.Flusher); ok {
		flusher.Flush()
	}
}
