// backend/middleware.go
package main

import (
	"net/http"
	"strings"
	"time"

	"github.com/tus/tusd/pkg/handler"

	"scm.bstein.dev/bstein/Pegasus/backend/internal"
)

type loggingRW struct {
	http.ResponseWriter
	status int
}

func (l *loggingRW) WriteHeader(code int) {
	l.status = code
	l.ResponseWriter.WriteHeader(code)
}

func sessionRequired(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if _, err := internal.CurrentUser(r); err != nil {
			http.Error(w, "unauthorized", http.StatusUnauthorized)
			return
		}
		next.ServeHTTP(w, r)
	})
}

func corsForTus(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if origin := r.Header.Get("Origin"); origin != "" {
			w.Header().Set("Access-Control-Allow-Origin", origin)
			w.Header().Set("Vary", "Origin")
		}
		w.Header().Set("Access-Control-Allow-Credentials", "true")
		w.Header().Set("Access-Control-Allow-Methods", "GET,POST,HEAD,PATCH,DELETE,OPTIONS")
		w.Header().Set("Access-Control-Max-Age", "86400")
		w.Header().Set(
			"Access-Control-Allow-Headers",
			"Content-Type, Tus-Resumable, Upload-Length, Upload-Defer-Length, Upload-Metadata, Upload-Offset, Upload-Concat, Upload-Checksum, X-Requested-With",
		)
		w.Header().Set("Access-Control-Expose-Headers", "Location, Upload-Offset, Upload-Length, Tus-Resumable, Upload-Checksum")
		if r.Method == http.MethodOptions {
			w.WriteHeader(http.StatusNoContent)
			return
		}
		next.ServeHTTP(w, r)
	})
}

func claimsFromHook(ev handler.HookEvent) (internal.Claims, error) {
	req := ev.HTTPRequest
	if req.Header == nil {
		return internal.Claims{}, http.ErrNoCookie
	}
	r := http.Request{Header: http.Header(req.Header)}
	return internal.CurrentUser(&r)
}

func redactHeaders(h http.Header) http.Header {
	cp := http.Header{}
	for k, v := range h {
		kk := strings.ToLower(k)
		if kk == "cookie" || strings.HasPrefix(kk, "authorization") || strings.Contains(kk, "token") {
			cp[k] = []string{"<redacted>"}
			continue
		}
		cp[k] = append([]string(nil), v...)
	}
	return cp
}

func debugHandler(next http.Handler) http.Handler {
	if !internal.Debug {
		return next
	}
	return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
		id := time.Now().UnixNano()
		internal.Logf(">> %d %s %s %v", id, req.Method, req.URL.Path, redactHeaders(req.Header))
		rw := &loggingRW{ResponseWriter: w, status: http.StatusOK}
		start := time.Now()
		next.ServeHTTP(rw, req)
		internal.Logf("<< %d %s %s %d %s", id, req.Method, req.URL.Path, rw.status, time.Since(start))
	})
}
