package controller

{{- if $.Imports }}

import (
	{{- range $import := $.Imports }}
	{{$import.Name}} "{{$import.Path}}"
	{{- end }}
)
{{- end }}

type Handler struct {
	*Controller
}

func (h *Handler) Register(r *router.Router) {
	h.Controller.register(r)
}

{{- define "controller" }}

// Controller struct
type {{ $.Pascal }}Controller struct {
	{{- range $action := $.Actions }}
	{{$action.Pascal}} *{{ $.Pascal }}{{$action.Pascal}}Action
	{{- end }}
	{{- range $controller := $.Controllers }}
	{{$controller.Last.Pascal}}Controller *{{$controller.Pascal}}Controller
	{{- end }}
}

func (c *{{ $.Pascal }}Controller) register(r *router.Router) {
	{{- range $action := $.Actions }}
	r.{{ $action.Method }}(`{{ $action.Route }}`, c.{{$action.Pascal}})
	{{- end }}
	{{- range $controller := $.Controllers }}
	c.{{$controller.Last.Pascal}}Controller.register(r)
	{{- end }}
}

{{- range $action := $.Actions }}

// {{ $.Pascal }}{{$action.Pascal}}Action struct
type {{ $.Pascal }}{{$action.Pascal}}Action struct {
	{{- if $action.View }}
	View *view.Handler
	{{- end }}
	{{- with $provider := $action.Provider }}
	{{- range $param := $provider.Hoisted }}
	{{$param.Key}} {{$param.FullType}}
	{{- end }}
	{{- end }}
}

// Key is a unique identifier of this action
func ({{$action.Short}} *{{ $.Pascal }}{{$action.Pascal}}Action) Key() string {
	return "{{$action.Key}}"
}

// Path is the default RESTful path to this action
func ({{$action.Short}} *{{ $.Pascal }}{{$action.Pascal}}Action) Path() string {
	return "{{$action.Route}}"
}

// Method is the default RESTful method of this action
func ({{$action.Short}} *{{ $.Pascal }}{{$action.Pascal}}Action) Method() string {
	return "{{$action.Method}}"
}

// ServeHTTP fn
func ({{$action.Short}} *{{ $.Pascal }}{{$action.Pascal}}Action) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	{{$action.Short}}.handler(w, r).ServeHTTP(w, r)
}

// Handler function
func ({{$action.Short}} *{{ $.Pascal }}{{$action.Pascal}}Action) handler(httpResponse http.ResponseWriter, httpRequest *http.Request) http.Handler {
	{{- if $action.Params }}
	// Define the input struct
	var in {{ $action.Input}}
	// Unmarshal the request body
	if err := request.Unmarshal(httpRequest, &in); err != nil {
		return &response.Format{
			{{- if ne $action.Method "Get" }}
			HTML: response.Status(http.StatusSeeOther).RedirectBack(httpRequest.URL.Path),
			{{- end }}
			JSON: response.Status(400).Set("Content-Type", "application/json").JSON(map[string]string{"error": err.Error()}),
		}
	}
	{{- end }}
	{{- with $provider := $action.Provider }}
	controller, err := {{ $provider.Name }}(
		{{- range $param := $provider.Hoisted }}
		{{ $action.Short }}.{{ $param.Key }},
		{{- end }}
		{{- if $provider.Variable "context.Context" }}httpRequest.Context(),{{ end }}
		{{- if $provider.Variable "net/http.*Request" }}httpRequest,{{ end }}
		{{- if $provider.Variable "net/http.ResponseWriter" }}httpResponse,{{ end }}
	)
	{{- end }}
	if err != nil {
		return &response.Format{
			{{- if ne $action.Method "Get" }}
			HTML: response.Status(http.StatusSeeOther).RedirectBack(httpRequest.URL.Path),
			{{- end }}
			JSON: response.Status(500).Set("Content-Type", "application/json").JSON(map[string]string{"error": err.Error()}),
		}
	}
	handler := controller.{{$action.Name}}
	{{- if $action.HandlerFunc }}
	return http.HandlerFunc(handler)
	{{- else }}
	// Call the controller
	{{ $action.Results.Set }}handler(
		{{- range $param := $action.Params }}
		{{ $param.Variable }},
		{{- end }}
	)
	{{- if $action.Results.Error }}
	if {{ $action.Results.Error }} != nil {
		return &response.Format{
			{{- if ne $action.Method "Get" }}
			HTML: response.Status(http.StatusSeeOther).RedirectBack(httpRequest.URL.Path),
			{{- end }}
			JSON: response.Status(500).Set("Content-Type", "application/json").JSON(map[string]string{"error": {{ $action.Results.Error }}.Error()}),
		}
	}
	{{- end }}

	// Respond
	return &response.Format{
		{{- if eq $action.Method "Get" }}
		{{- if $action.View }}
		HTML: {{ $action.Short }}.View.Renderer("{{$action.View.Route}}", {{ $action.Results.ViewResult }}),
		{{- else if $action.RespondHTML }}
		HTML: response.HTML({{ $action.Results.Result }}),
		{{- end }}
		{{- else }}
		HTML: response.Status(302).Redirect(response.RedirectPath(httpRequest, {{$action.Redirect}})),
		{{- end }}
		{{- if $action.RespondJSON }}
		{{- if $action.Results.Result }}
		JSON: response.JSON({{ $action.Results.Result }}),
		{{- else if $action.Results.IsOnlyError }}
		JSON: response.Status(204),
		{{- else }}
		JSON: response.Status(200).Set("Content-Type", "application/json"),
		{{- end }}
		{{- else }}
		JSON: response.Status(204),
		{{- end }}
	}
	{{- end }}
}
{{- end }}

{{- range $controller := $.Controllers }}

{{- template "controller" $controller }}
{{- end }}

{{- end }}

{{- template "controller" $.Controller }}

{{- range $provider := $.Providers }}

{{ $provider.Function }}
{{- end }}
