// Package http_server provides primitives to interact with the openapi HTTP API.
//
// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.5.0 DO NOT EDIT.
package http_server

import (
	"context"
	"encoding/json"
	"fmt"
	"net/http"
	"time"

	"github.com/go-chi/chi/v5"
	"github.com/oapi-codegen/runtime"
	strictnethttp "github.com/oapi-codegen/runtime/strictmiddleware/nethttp"
	openapi_types "github.com/oapi-codegen/runtime/types"
)

// CreateProfileInput defines model for CreateProfileInput.
type CreateProfileInput struct {
	// Age Age of the user
	Age int `json:"age"`

	// Email Email address of the user
	Email string `json:"email"`

	// Name Full name of the user
	Name string `json:"name"`

	// Phone Phone number of the user
	Phone string `json:"phone"`
}

// CreateProfileOutput defines model for CreateProfileOutput.
type CreateProfileOutput struct {
	// ID Unique identifier of the created profile
	ID openapi_types.UUID `json:"id"`
}

// ErrorResponse defines model for ErrorResponse.
type ErrorResponse struct {
	// Error Error message
	Error string `json:"error"`
}

// GetProfileOutput defines model for GetProfileOutput.
type GetProfileOutput struct {
	// Age Age of the user
	Age      int `json:"age"`
	Contacts struct {
		// Email Email address of the user
		Email string `json:"email"`

		// Phone Phone number of the user
		Phone string `json:"phone"`
	} `json:"contacts"`

	// CreatedAt Date and time when the profile was created
	CreatedAt time.Time `json:"created_at"`

	// ID Unique identifier of the profile
	ID openapi_types.UUID `json:"id"`

	// Name Full name of the user
	Name string `json:"name"`

	// Status Status of the profile
	Status int `json:"status"`

	// UpdatedAt Date and time when the profile was last updated
	UpdatedAt time.Time `json:"updated_at"`

	// Verified Verification status of the profile
	Verified bool `json:"verified"`
}

// UpdateProfileInput defines model for UpdateProfileInput.
type UpdateProfileInput struct {
	// Age Age of the user
	Age *int `json:"age"`

	// Email Email address of the user
	Email *string `json:"email"`

	// ID Unique identifier of the profile
	ID openapi_types.UUID `json:"id"`

	// Name Full name of the user
	Name *string `json:"name"`

	// Phone Phone number of the user
	Phone *string `json:"phone"`
}

// CreateProfileJSONRequestBody defines body for CreateProfile for application/json ContentType.
type CreateProfileJSONRequestBody = CreateProfileInput

// UpdateProfileJSONRequestBody defines body for UpdateProfile for application/json ContentType.
type UpdateProfileJSONRequestBody = UpdateProfileInput

// ServerInterface represents all server handlers.
type ServerInterface interface {
	// Create a new profile
	// (POST /profile)
	CreateProfile(w http.ResponseWriter, r *http.Request)
	// Update an existing profile
	// (PUT /profile)
	UpdateProfile(w http.ResponseWriter, r *http.Request)
	// Delete a profile by ID
	// (DELETE /profile/{id})
	DeleteProfileByID(w http.ResponseWriter, r *http.Request, id openapi_types.UUID)
	// Get a profile by ID
	// (GET /profile/{id})
	GetProfileByID(w http.ResponseWriter, r *http.Request, id openapi_types.UUID)
}

// Unimplemented server implementation that returns http.StatusNotImplemented for each endpoint.

type Unimplemented struct{}

// Create a new profile
// (POST /profile)
func (_ Unimplemented) CreateProfile(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(http.StatusNotImplemented)
}

// Update an existing profile
// (PUT /profile)
func (_ Unimplemented) UpdateProfile(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(http.StatusNotImplemented)
}

// Delete a profile by ID
// (DELETE /profile/{id})
func (_ Unimplemented) DeleteProfileByID(w http.ResponseWriter, r *http.Request, id openapi_types.UUID) {
	w.WriteHeader(http.StatusNotImplemented)
}

// Get a profile by ID
// (GET /profile/{id})
func (_ Unimplemented) GetProfileByID(w http.ResponseWriter, r *http.Request, id openapi_types.UUID) {
	w.WriteHeader(http.StatusNotImplemented)
}

// ServerInterfaceWrapper converts contexts to parameters.
type ServerInterfaceWrapper struct {
	Handler            ServerInterface
	HandlerMiddlewares []MiddlewareFunc
	ErrorHandlerFunc   func(w http.ResponseWriter, r *http.Request, err error)
}

type MiddlewareFunc func(http.Handler) http.Handler

// CreateProfile operation middleware
func (siw *ServerInterfaceWrapper) CreateProfile(w http.ResponseWriter, r *http.Request) {

	handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		siw.Handler.CreateProfile(w, r)
	}))

	for _, middleware := range siw.HandlerMiddlewares {
		handler = middleware(handler)
	}

	handler.ServeHTTP(w, r)
}

// UpdateProfile operation middleware
func (siw *ServerInterfaceWrapper) UpdateProfile(w http.ResponseWriter, r *http.Request) {

	handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		siw.Handler.UpdateProfile(w, r)
	}))

	for _, middleware := range siw.HandlerMiddlewares {
		handler = middleware(handler)
	}

	handler.ServeHTTP(w, r)
}

// DeleteProfileByID operation middleware
func (siw *ServerInterfaceWrapper) DeleteProfileByID(w http.ResponseWriter, r *http.Request) {

	var err error

	// ------------- Path parameter "id" -------------
	var id openapi_types.UUID

	err = runtime.BindStyledParameterWithOptions("simple", "id", chi.URLParam(r, "id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true})
	if err != nil {
		siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "id", Err: err})
		return
	}

	handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		siw.Handler.DeleteProfileByID(w, r, id)
	}))

	for _, middleware := range siw.HandlerMiddlewares {
		handler = middleware(handler)
	}

	handler.ServeHTTP(w, r)
}

// GetProfileByID operation middleware
func (siw *ServerInterfaceWrapper) GetProfileByID(w http.ResponseWriter, r *http.Request) {

	var err error

	// ------------- Path parameter "id" -------------
	var id openapi_types.UUID

	err = runtime.BindStyledParameterWithOptions("simple", "id", chi.URLParam(r, "id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true})
	if err != nil {
		siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "id", Err: err})
		return
	}

	handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		siw.Handler.GetProfileByID(w, r, id)
	}))

	for _, middleware := range siw.HandlerMiddlewares {
		handler = middleware(handler)
	}

	handler.ServeHTTP(w, r)
}

type UnescapedCookieParamError struct {
	ParamName string
	Err       error
}

func (e *UnescapedCookieParamError) Error() string {
	return fmt.Sprintf("error unescaping cookie parameter '%s'", e.ParamName)
}

func (e *UnescapedCookieParamError) Unwrap() error {
	return e.Err
}

type UnmarshalingParamError struct {
	ParamName string
	Err       error
}

func (e *UnmarshalingParamError) Error() string {
	return fmt.Sprintf("Error unmarshaling parameter %s as JSON: %s", e.ParamName, e.Err.Error())
}

func (e *UnmarshalingParamError) Unwrap() error {
	return e.Err
}

type RequiredParamError struct {
	ParamName string
}

func (e *RequiredParamError) Error() string {
	return fmt.Sprintf("Query argument %s is required, but not found", e.ParamName)
}

type RequiredHeaderError struct {
	ParamName string
	Err       error
}

func (e *RequiredHeaderError) Error() string {
	return fmt.Sprintf("Header parameter %s is required, but not found", e.ParamName)
}

func (e *RequiredHeaderError) Unwrap() error {
	return e.Err
}

type InvalidParamFormatError struct {
	ParamName string
	Err       error
}

func (e *InvalidParamFormatError) Error() string {
	return fmt.Sprintf("Invalid format for parameter %s: %s", e.ParamName, e.Err.Error())
}

func (e *InvalidParamFormatError) Unwrap() error {
	return e.Err
}

type TooManyValuesForParamError struct {
	ParamName string
	Count     int
}

func (e *TooManyValuesForParamError) Error() string {
	return fmt.Sprintf("Expected one value for %s, got %d", e.ParamName, e.Count)
}

// Handler creates http.Handler with routing matching OpenAPI spec.
func Handler(si ServerInterface) http.Handler {
	return HandlerWithOptions(si, ChiServerOptions{})
}

type ChiServerOptions struct {
	BaseURL          string
	BaseRouter       chi.Router
	Middlewares      []MiddlewareFunc
	ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
}

// HandlerFromMux creates http.Handler with routing matching OpenAPI spec based on the provided mux.
func HandlerFromMux(si ServerInterface, r chi.Router) http.Handler {
	return HandlerWithOptions(si, ChiServerOptions{
		BaseRouter: r,
	})
}

func HandlerFromMuxWithBaseURL(si ServerInterface, r chi.Router, baseURL string) http.Handler {
	return HandlerWithOptions(si, ChiServerOptions{
		BaseURL:    baseURL,
		BaseRouter: r,
	})
}

// HandlerWithOptions creates http.Handler with additional options
func HandlerWithOptions(si ServerInterface, options ChiServerOptions) http.Handler {
	r := options.BaseRouter

	if r == nil {
		r = chi.NewRouter()
	}
	if options.ErrorHandlerFunc == nil {
		options.ErrorHandlerFunc = func(w http.ResponseWriter, r *http.Request, err error) {
			http.Error(w, err.Error(), http.StatusBadRequest)
		}
	}
	wrapper := ServerInterfaceWrapper{
		Handler:            si,
		HandlerMiddlewares: options.Middlewares,
		ErrorHandlerFunc:   options.ErrorHandlerFunc,
	}

	r.Group(func(r chi.Router) {
		r.Post(options.BaseURL+"/profile", wrapper.CreateProfile)
	})
	r.Group(func(r chi.Router) {
		r.Put(options.BaseURL+"/profile", wrapper.UpdateProfile)
	})
	r.Group(func(r chi.Router) {
		r.Delete(options.BaseURL+"/profile/{id}", wrapper.DeleteProfileByID)
	})
	r.Group(func(r chi.Router) {
		r.Get(options.BaseURL+"/profile/{id}", wrapper.GetProfileByID)
	})

	return r
}

type CreateProfileRequestObject struct {
	Body *CreateProfileJSONRequestBody
}

type CreateProfileResponseObject interface {
	VisitCreateProfileResponse(w http.ResponseWriter) error
}

type CreateProfile200JSONResponse CreateProfileOutput

func (response CreateProfile200JSONResponse) VisitCreateProfileResponse(w http.ResponseWriter) error {
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(200)

	return json.NewEncoder(w).Encode(response)
}

type CreateProfile400JSONResponse ErrorResponse

func (response CreateProfile400JSONResponse) VisitCreateProfileResponse(w http.ResponseWriter) error {
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(400)

	return json.NewEncoder(w).Encode(response)
}

type UpdateProfileRequestObject struct {
	Body *UpdateProfileJSONRequestBody
}

type UpdateProfileResponseObject interface {
	VisitUpdateProfileResponse(w http.ResponseWriter) error
}

type UpdateProfile204Response struct {
}

func (response UpdateProfile204Response) VisitUpdateProfileResponse(w http.ResponseWriter) error {
	w.WriteHeader(204)
	return nil
}

type UpdateProfile400JSONResponse ErrorResponse

func (response UpdateProfile400JSONResponse) VisitUpdateProfileResponse(w http.ResponseWriter) error {
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(400)

	return json.NewEncoder(w).Encode(response)
}

type DeleteProfileByIDRequestObject struct {
	ID openapi_types.UUID `json:"id"`
}

type DeleteProfileByIDResponseObject interface {
	VisitDeleteProfileByIDResponse(w http.ResponseWriter) error
}

type DeleteProfileByID204Response struct {
}

func (response DeleteProfileByID204Response) VisitDeleteProfileByIDResponse(w http.ResponseWriter) error {
	w.WriteHeader(204)
	return nil
}

type DeleteProfileByID400JSONResponse ErrorResponse

func (response DeleteProfileByID400JSONResponse) VisitDeleteProfileByIDResponse(w http.ResponseWriter) error {
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(400)

	return json.NewEncoder(w).Encode(response)
}

type GetProfileByIDRequestObject struct {
	ID openapi_types.UUID `json:"id"`
}

type GetProfileByIDResponseObject interface {
	VisitGetProfileByIDResponse(w http.ResponseWriter) error
}

type GetProfileByID200JSONResponse GetProfileOutput

func (response GetProfileByID200JSONResponse) VisitGetProfileByIDResponse(w http.ResponseWriter) error {
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(200)

	return json.NewEncoder(w).Encode(response)
}

type GetProfileByID400JSONResponse ErrorResponse

func (response GetProfileByID400JSONResponse) VisitGetProfileByIDResponse(w http.ResponseWriter) error {
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(400)

	return json.NewEncoder(w).Encode(response)
}

type GetProfileByID404JSONResponse ErrorResponse

func (response GetProfileByID404JSONResponse) VisitGetProfileByIDResponse(w http.ResponseWriter) error {
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(404)

	return json.NewEncoder(w).Encode(response)
}

// StrictServerInterface represents all server handlers.
type StrictServerInterface interface {
	// Create a new profile
	// (POST /profile)
	CreateProfile(ctx context.Context, request CreateProfileRequestObject) (CreateProfileResponseObject, error)
	// Update an existing profile
	// (PUT /profile)
	UpdateProfile(ctx context.Context, request UpdateProfileRequestObject) (UpdateProfileResponseObject, error)
	// Delete a profile by ID
	// (DELETE /profile/{id})
	DeleteProfileByID(ctx context.Context, request DeleteProfileByIDRequestObject) (DeleteProfileByIDResponseObject, error)
	// Get a profile by ID
	// (GET /profile/{id})
	GetProfileByID(ctx context.Context, request GetProfileByIDRequestObject) (GetProfileByIDResponseObject, error)
}

type StrictHandlerFunc = strictnethttp.StrictHTTPHandlerFunc
type StrictMiddlewareFunc = strictnethttp.StrictHTTPMiddlewareFunc

type StrictHTTPServerOptions struct {
	RequestErrorHandlerFunc  func(w http.ResponseWriter, r *http.Request, err error)
	ResponseErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
}

func NewStrictHandler(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc) ServerInterface {
	return &strictHandler{ssi: ssi, middlewares: middlewares, options: StrictHTTPServerOptions{
		RequestErrorHandlerFunc: func(w http.ResponseWriter, r *http.Request, err error) {
			http.Error(w, err.Error(), http.StatusBadRequest)
		},
		ResponseErrorHandlerFunc: func(w http.ResponseWriter, r *http.Request, err error) {
			http.Error(w, err.Error(), http.StatusInternalServerError)
		},
	}}
}

func NewStrictHandlerWithOptions(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc, options StrictHTTPServerOptions) ServerInterface {
	return &strictHandler{ssi: ssi, middlewares: middlewares, options: options}
}

type strictHandler struct {
	ssi         StrictServerInterface
	middlewares []StrictMiddlewareFunc
	options     StrictHTTPServerOptions
}

// CreateProfile operation middleware
func (sh *strictHandler) CreateProfile(w http.ResponseWriter, r *http.Request) {
	var request CreateProfileRequestObject

	var body CreateProfileJSONRequestBody
	if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
		sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode JSON body: %w", err))
		return
	}
	request.Body = &body

	handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) {
		return sh.ssi.CreateProfile(ctx, request.(CreateProfileRequestObject))
	}
	for _, middleware := range sh.middlewares {
		handler = middleware(handler, "CreateProfile")
	}

	response, err := handler(r.Context(), w, r, request)

	if err != nil {
		sh.options.ResponseErrorHandlerFunc(w, r, err)
	} else if validResponse, ok := response.(CreateProfileResponseObject); ok {
		if err := validResponse.VisitCreateProfileResponse(w); err != nil {
			sh.options.ResponseErrorHandlerFunc(w, r, err)
		}
	} else if response != nil {
		sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response))
	}
}

// UpdateProfile operation middleware
func (sh *strictHandler) UpdateProfile(w http.ResponseWriter, r *http.Request) {
	var request UpdateProfileRequestObject

	var body UpdateProfileJSONRequestBody
	if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
		sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode JSON body: %w", err))
		return
	}
	request.Body = &body

	handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) {
		return sh.ssi.UpdateProfile(ctx, request.(UpdateProfileRequestObject))
	}
	for _, middleware := range sh.middlewares {
		handler = middleware(handler, "UpdateProfile")
	}

	response, err := handler(r.Context(), w, r, request)

	if err != nil {
		sh.options.ResponseErrorHandlerFunc(w, r, err)
	} else if validResponse, ok := response.(UpdateProfileResponseObject); ok {
		if err := validResponse.VisitUpdateProfileResponse(w); err != nil {
			sh.options.ResponseErrorHandlerFunc(w, r, err)
		}
	} else if response != nil {
		sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response))
	}
}

// DeleteProfileByID operation middleware
func (sh *strictHandler) DeleteProfileByID(w http.ResponseWriter, r *http.Request, id openapi_types.UUID) {
	var request DeleteProfileByIDRequestObject

	request.ID = id

	handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) {
		return sh.ssi.DeleteProfileByID(ctx, request.(DeleteProfileByIDRequestObject))
	}
	for _, middleware := range sh.middlewares {
		handler = middleware(handler, "DeleteProfileByID")
	}

	response, err := handler(r.Context(), w, r, request)

	if err != nil {
		sh.options.ResponseErrorHandlerFunc(w, r, err)
	} else if validResponse, ok := response.(DeleteProfileByIDResponseObject); ok {
		if err := validResponse.VisitDeleteProfileByIDResponse(w); err != nil {
			sh.options.ResponseErrorHandlerFunc(w, r, err)
		}
	} else if response != nil {
		sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response))
	}
}

// GetProfileByID operation middleware
func (sh *strictHandler) GetProfileByID(w http.ResponseWriter, r *http.Request, id openapi_types.UUID) {
	var request GetProfileByIDRequestObject

	request.ID = id

	handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) {
		return sh.ssi.GetProfileByID(ctx, request.(GetProfileByIDRequestObject))
	}
	for _, middleware := range sh.middlewares {
		handler = middleware(handler, "GetProfileByID")
	}

	response, err := handler(r.Context(), w, r, request)

	if err != nil {
		sh.options.ResponseErrorHandlerFunc(w, r, err)
	} else if validResponse, ok := response.(GetProfileByIDResponseObject); ok {
		if err := validResponse.VisitGetProfileByIDResponse(w); err != nil {
			sh.options.ResponseErrorHandlerFunc(w, r, err)
		}
	} else if response != nil {
		sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response))
	}
}
