package shared

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

	"github.com/porter-dev/porter/api/server/shared/apierrors"
	"github.com/porter-dev/porter/api/server/shared/apierrors/alerter"
	"github.com/porter-dev/porter/pkg/logger"
)

type ResultWriter interface {
	WriteResult(w http.ResponseWriter, r *http.Request, v interface{})
}

// default generalizes response codes for common operations
// (http.StatusOK, http.StatusCreated, etc)
type DefaultResultWriter struct {
	logger  *logger.Logger
	alerter alerter.Alerter
}

func NewDefaultResultWriter(
	logger *logger.Logger,
	alerter alerter.Alerter,
) ResultWriter {
	return &DefaultResultWriter{logger, alerter}
}

func (j *DefaultResultWriter) WriteResult(w http.ResponseWriter, r *http.Request, v interface{}) {
	err := json.NewEncoder(w).Encode(v)

	if errors.Is(err, syscall.EPIPE) || errors.Is(err, syscall.ECONNRESET) {
		// either a broken pipe error or econnreset, ignore. This means the client closed the connection while
		// the server was sending bytes.
		return
	} else if err != nil {
		apierrors.HandleAPIError(j.logger, j.alerter, w, r, apierrors.NewErrInternal(err), true)
	}
}
