package web

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"strconv"
	"strings"

	"goauthentik.io/internal/config"
)

type SentryRequest struct {
	DSN string `json:"dsn"`
}

func (ws *WebServer) APISentryProxy() http.HandlerFunc {
	fallbackHandler := func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusBadRequest)
	}
	if !config.Get().ErrorReporting.Enabled {
		ws.log.Debug("error reporting disabled")
		return fallbackHandler
	}
	dsn, err := url.Parse(config.Get().ErrorReporting.SentryDSN)
	if err != nil {
		ws.log.WithError(err).Warning("invalid sentry DSN")
		return fallbackHandler
	}
	projectId, err := strconv.Atoi(strings.TrimPrefix(dsn.Path, "/"))
	if err != nil {
		ws.log.WithError(err).Warning("failed to get sentry project id")
		return fallbackHandler
	}
	return func(rw http.ResponseWriter, r *http.Request) {
		fb := &bytes.Buffer{}
		_, err := io.Copy(fb, r.Body)
		if err != nil {
			ws.log.Debug("failed to read body")
			rw.WriteHeader(http.StatusBadRequest)
			return
		}
		lines := strings.Split(fb.String(), "\n")
		if len(lines) < 1 {
			rw.WriteHeader(http.StatusBadRequest)
			return
		}
		sd := SentryRequest{}
		err = json.Unmarshal([]byte(lines[0]), &sd)
		if err != nil {
			ws.log.WithError(err).Warning("failed to parse sentry request")
			rw.WriteHeader(http.StatusBadRequest)
			return
		}
		if sd.DSN != config.Get().ErrorReporting.SentryDSN {
			rw.WriteHeader(http.StatusBadRequest)
			return
		}
		res, err := http.DefaultClient.Post(
			fmt.Sprintf(
				"https://%s/api/%d/envelope/",
				dsn.Host,
				projectId,
			),
			"application/x-sentry-envelope",
			fb,
		)
		if err != nil {
			ws.log.WithError(err).Warning("failed to proxy sentry")
			rw.WriteHeader(http.StatusBadRequest)
			return
		}
		rw.WriteHeader(res.StatusCode)
	}
}