package middleware

import (
	"net/http"
	"slices"
	"strings"
)

// CORS restricts cross-origin requests to the configured origins (api-design.md §12).
// An empty allowlist is fail-closed: no cross-origin requests are permitted and
// credentials are never echoed. Same-origin requests (no Origin header) are
// unaffected. Deliberately configured origins must be listed explicitly.
func CORS(allowed []string) func(http.Handler) http.Handler {
	norm := make([]string, 0, len(allowed))
	for _, o := range allowed {
		if o = strings.ToLower(strings.TrimSpace(o)); o != "" {
			norm = append(norm, o)
		}
	}
	return func(next http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			origin := r.Header.Get("Origin")
			if origin == "" {
				// Same-origin (browser) or non-browser client; no CORS needed.
				next.ServeHTTP(w, r)
				return
			}
			allowAll := slices.Contains(norm, "*")
			if allowAll {
				// Wildcard cannot be combined with credentialed origin-echo:
				// echoing any Origin plus Allow-Credentials=true lets any site
				// read authenticated responses. Wildcard stays non-credentialed;
				// list origins explicitly to get credentialed CORS.
				w.Header().Set("Vary", "Origin")
				w.Header().Set("Access-Control-Allow-Origin", "*")
				w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, PATCH, DELETE, OPTIONS")
				w.Header().Set("Access-Control-Allow-Headers", "Authorization, Content-Type, X-Request-Id, Idempotency-Key")
				w.Header().Set("Access-Control-Max-Age", "86400")
				if r.Method == http.MethodOptions {
					w.WriteHeader(http.StatusNoContent)
					return
				}
				next.ServeHTTP(w, r)
				return
			}
			if slices.Contains(norm, strings.ToLower(strings.TrimSpace(origin))) {
				w.Header().Set("Vary", "Origin")
				w.Header().Set("Access-Control-Allow-Origin", origin)
				w.Header().Set("Access-Control-Allow-Credentials", "true")
				w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, PATCH, DELETE, OPTIONS")
				w.Header().Set("Access-Control-Allow-Headers", "Authorization, Content-Type, X-Request-Id, Idempotency-Key")
				w.Header().Set("Access-Control-Max-Age", "86400")
				if r.Method == http.MethodOptions {
					w.WriteHeader(http.StatusNoContent)
					return
				}
				next.ServeHTTP(w, r)
				return
			}
			if r.Method == http.MethodOptions {
				// Preflight from a disallowed origin: reject explicitly.
				w.WriteHeader(http.StatusForbidden)
				return
			}
			// Cross-origin request from a disallowed origin: do not expose
			// CORS headers, so the browser blocks reading the response.
			next.ServeHTTP(w, r)
		})
	}
}
