package responses

import (
	"fmt"
	"io"
	"net/http"
	"net/url"
	"time"

	"git.kirsle.net/apps/gophertype/pkg/authentication"
	"git.kirsle.net/apps/gophertype/pkg/models"
	"git.kirsle.net/apps/gophertype/pkg/session"
	"git.kirsle.net/apps/gophertype/pkg/settings"
)

// NewTemplateVars creates the TemplateVars for your current request.
func NewTemplateVars(w io.Writer, r *http.Request) TemplateValues {
	var s = settings.Current
	user, _ := authentication.CurrentUser(r)

	ses := session.Get(r)

	v := TemplateValues{
		SetupNeeded: !s.Initialized,

		Title:       s.Title,
		Description: s.Description,

		Request:         r,
		RequestTime:     time.Now(),
		RequestDuration: time.Duration(0),
		Session:         ses,
		Path:            r.URL.Path,

		LoggedIn:    authentication.LoggedIn(r),
		IsAdmin:     user.IsAdmin,
		CurrentUser: user,

		V: map[string]interface{}{},
	}

	if rw, ok := w.(http.ResponseWriter); ok {
		v.ResponseWriter = rw
		flashes, errors := ses.ReadFlashes(rw)
		v.Flashes = append(flashes, errors...)
	}

	return v
}

// TemplateValues holds the context for html templates.
type TemplateValues struct {
	// When the site needs the initial config.
	SetupNeeded bool

	// Config values available as template variables.
	Title       string
	Description string

	// Request variables
	Request         *http.Request
	RequestTime     time.Time
	RequestDuration time.Duration
	ResponseWriter  http.ResponseWriter
	FormValues      url.Values
	Path            string // request path
	TemplatePath    string // file path of html template, like "_builtin/error.gohtml"

	// Session variables
	Session     *session.Session
	LoggedIn    bool
	IsAdmin     bool
	CurrentUser models.User

	// Common template variables.
	Message         string
	Error           interface{}
	ValidationError map[string][]string // form validation errors
	Flashes         []string

	// Arbitrary controller-specific fields go in V.
	V map[string]interface{}
}

// Flash adds a message to flash on the next template render.
func (v *TemplateValues) Flash(msg string, args ...interface{}) {
	v.Flashes = append(v.Flashes, fmt.Sprintf(msg, args...))
}
