package internal

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

	"github.com/go-chi/chi/middleware"
)

type RestResponse struct {
	Status  int
	Headers http.Header
	Payload struct {
		Success bool        `json:"success"`
		Payload interface{} `json:"payload"`
	}
}

func BasicResponse(success bool, model interface{}) *RestResponse {
	return &RestResponse{
		Status: http.StatusOK,
		Payload: struct {
			Success bool        "json:\"success\""
			Payload interface{} "json:\"payload\""
		}{Success: success, Payload: model},
	}
}

func ErrorResponse(status int, err error) *RestResponse {
	return &RestResponse{
		Status: status,
		Payload: struct {
			Success bool        "json:\"success\""
			Payload interface{} "json:\"payload\""
		}{
			Success: false,
			Payload: err.Error(),
		},
	}
}

func (rr *RestResponse) Write(w http.ResponseWriter) error {
	if rr.Status != 0 && rr.Status != 200 {
		w.WriteHeader(rr.Status)
	}

	for k, v := range rr.Headers {
		for _, ve := range v {
			w.Header().Add(k, ve)
		}
	}

	e := json.NewEncoder(w)
	e.SetIndent("\n", "\t")

	if err := e.Encode(rr.Payload); err != nil {
		return fmt.Errorf("could not serialize struct for http response: %w", err)
	}

	return nil
}

type RestHandler func(request *http.Request) (*RestResponse, error)

func (rh RestHandler) ToHF() http.HandlerFunc {
	return func(rw http.ResponseWriter, r *http.Request) {

		rid := r.Context().Value(middleware.RequestIDKey)
		rw.Header().Set(middleware.RequestIDHeader, rid.(string))
		rh.ServeHTTP(rw, r)
	}
}

func (rh RestHandler) Error(e error) *RestResponse {
	return &RestResponse{
		Status: http.StatusInternalServerError,
		Payload: struct {
			Success bool        `json:"success"`
			Payload interface{} `json:"payload"`
		}{
			Success: false,
			Payload: e.Error(),
		},
	}
}

func (r RestHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	response, err := r(req)
	if err != nil {
		response = r.Error(err)
	}

	if err := response.Write(w); err != nil {
		log.Printf("Error occurred handling rest response: %v", err)
	}
}
