package middleware

import (
	"log/slog"
	"net"
	"net/http"
	"net/http/httputil"
	"os"
	"runtime/debug"
	"strings"

	"github.com/gin-gonic/gin"
)

func Recovery(logger *slog.Logger) gin.HandlerFunc {
	return func(c *gin.Context) {
		defer func() {
			panicValue := recover()
			if panicValue == nil {
				return
			}
			brokenPipe := false
			if networkError, ok := panicValue.(*net.OpError); ok {
				if syscallError, ok := networkError.Err.(*os.SyscallError); ok {
					message := strings.ToLower(syscallError.Error())
					brokenPipe = strings.Contains(message, "broken pipe") || strings.Contains(message, "connection reset by peer")
				}
			}
			request, _ := httputil.DumpRequest(c.Request, false)
			if logger != nil {
				logger.ErrorContext(c.Request.Context(), "recovery from panic", "mod", "http", "error", panicValue, "request", string(request), "stack", string(debug.Stack()))
			}
			if brokenPipe {
				if err, ok := panicValue.(error); ok {
					_ = c.Error(err)
				}
				c.Abort()
				return
			}
			c.AbortWithStatus(http.StatusInternalServerError)
		}()
		c.Next()
	}
}
