package state

import (
	"encoding/json"
	"errors"
	"net/http"

	comatproto "github.com/bluesky-social/indigo/api/atproto"
	indigoxrpc "github.com/bluesky-social/indigo/xrpc"
	"tangled.org/core/xrpc"
)

// proxy requests to {pds}/xrpc/com.atproto.repo.uploadBlob
func (s *State) XrpcComAtprotoRepoUploadBlob(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()
	defer r.Body.Close()

	l := s.logger.With("handler", "XrpcComAtprotoRepoUploadBlob")

	client, err := s.oauth.AuthorizedClient(r)
	if err != nil {
		if err := json.NewEncoder(w).Encode(&indigoxrpc.XRPCError{
			ErrStr:  "AuthMissing",
			Message: "Authentication Required",
		}); err != nil {
			l.Error("failed to encode json", "err", err)
		}
		return
	}

	// pre-warm DPoP nonce
	if _, err := comatproto.ServerGetSession(ctx, client); err != nil {
		l.Error("failed to pre-warm session", "err", err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	out, err := xrpc.RepoUploadBlob(ctx, client, r.Body, r.Header.Get("Content-Type"))
	if err != nil {
		var xrpcErr *indigoxrpc.Error
		if ok := errors.As(err, &xrpcErr); ok {
			l.Error("xrpc response", "err", xrpcErr)

			w.WriteHeader(xrpcErr.StatusCode)
			var xrpcBody *indigoxrpc.XRPCError
			if ok := errors.As(xrpcErr.Wrapped, &xrpcBody); ok {
				w.Header().Set("Content-Type", "application/json")
				if err := json.NewEncoder(w).Encode(xrpcBody); err != nil {
					l.Error("failed to encode json", "err", err)
				}
			}
		} else {
			l.Error("failed to parse xrpc error body", "err", err)

			w.WriteHeader(http.StatusInternalServerError)
			if err := json.NewEncoder(w).Encode(&indigoxrpc.XRPCError{
				ErrStr:  "InternalError",
				Message: "Internal server error",
			}); err != nil {
				l.Error("failed to encode json", "err", err)
			}
		}
		return
	}

	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(http.StatusOK)
	if err := json.NewEncoder(w).Encode(out); err != nil {
		l.Error("failed to encode json", "err", err)
	}
}
