package responses

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

	"gitlab.bob.co.za/bob-public-utils/bobgroup-go-utils/map_utils"

	"gitlab.bob.co.za/bob-public-utils/bobgroup-go-utils/logs"
	"gitlab.bob.co.za/bob-public-utils/bobgroup-go-utils/utils"

	"github.com/aws/aws-lambda-go/events"
)

// =============================================================================
// RESPONSE HELPER / CONVENIENCE FUNCTIONS
// =============================================================================

var ContentTypeJSONHeader = map[string]string{"Content-Type": "application/json"}

// BadRequestResponse - invalid user input
func BadRequestResponse(err error) (events.APIGatewayProxyResponse, error) {
	return GenericResponse(http.StatusBadRequest, err.Error(), nil)
}

// NotFoundResponse - 404
func NotFoundResponse(err error) (events.APIGatewayProxyResponse, error) {
	return GenericResponse(http.StatusNotFound, err.Error(), nil)
}

func NoContent() (events.APIGatewayProxyResponse, error) {
	return events.APIGatewayProxyResponse{
		StatusCode: http.StatusNoContent,
		Headers:    map_utils.MergeMaps(utils.CorsHeaders(), ContentTypeJSONHeader),
	}, nil
}

func TooManyRequests(message string) (events.APIGatewayProxyResponse, error) {

	response := map[string]string{
		"message": message,
	}
	responseJson, err := json.Marshal(response)
	if err != nil {
		logs.Info("Could not create error message for ", message)
	}

	return events.APIGatewayProxyResponse{
		StatusCode: http.StatusTooManyRequests,
		Headers:    map_utils.MergeMaps(utils.CorsHeaders(), ContentTypeJSONHeader),
		Body:       string(responseJson),
	}, nil
}

func LockedResponse(err error) (events.APIGatewayProxyResponse, error) {
	return GenericResponse(http.StatusLocked, err.Error(), nil)
}

// InternalServerErrorResponse - something went wrong
func InternalServerErrorResponse(err error) (events.APIGatewayProxyResponse, error) {
	return GenericResponse(http.StatusInternalServerError, err.Error(), nil)
}

// SuccessResponse - everything worked
func SuccessResponse(body string) (events.APIGatewayProxyResponse, error) {
	return GenericResponse(http.StatusOK, body, nil)
}

// JSONSuccessResponse - try to JSONify any struct and send it as the body of a successful response
// Return an internal server error if JSON marshalling fails
// NOTE: struct fields must be exported (i.e. Capitalised) and tagged
func JSONSuccessResponse(body interface{}) (events.APIGatewayProxyResponse, error) {
	bodyBytes, err := json.Marshal(body)
	if err != nil {
		return InternalServerErrorResponse(err)
	}

	return GenericResponse(http.StatusOK, string(bodyBytes), ContentTypeJSONHeader)
}

// GenericResponse - called by the other functions
func GenericResponse(statusCode int, body string, headers map[string]string) (events.APIGatewayProxyResponse, error) {
	return events.APIGatewayProxyResponse{
		StatusCode: statusCode,
		Body:       body + "\n",
		Headers:    map_utils.MergeMaps(utils.CorsHeaders(), headers),
	}, nil
}

// SuccessResponse - everything worked
func GenericSuccessResponse(message string) (events.APIGatewayProxyResponse, error) {
	response := map[string]string{
		"message": message,
	}
	return JSONSuccessResponse(response)
}

func MaintenanceResponse(message string) events.APIGatewayProxyResponse {
	return events.APIGatewayProxyResponse{
		StatusCode: http.StatusTeapot,
		Body:       message,
		Headers:    map_utils.MergeMaps(utils.CorsHeaders(), ContentTypeJSONHeader),
	}
}

func RateLimitResponse(message string) events.APIGatewayProxyResponse {
	return events.APIGatewayProxyResponse{
		StatusCode: http.StatusTooManyRequests,
		Body:       message,
		Headers:    map_utils.MergeMaps(utils.CorsHeaders(), ContentTypeJSONHeader),
	}
}

func OptionsResponse() events.APIGatewayProxyResponse {
	return events.APIGatewayProxyResponse{
		StatusCode: http.StatusNoContent,
		Headers:    map_utils.MergeMaps(utils.CorsHeaders(), ContentTypeJSONHeader),
	}
}

func MovedPermanentlyResponse(url string) events.APIGatewayProxyResponse {
	return events.APIGatewayProxyResponse{
		StatusCode: http.StatusMovedPermanently,
		Headers:    map_utils.MergeMaps(utils.CorsHeaders(), map[string]string{"Location": url}),
	}
}