package controllers

import (
	"errors"
	"fmt"
	"net/http"

	"git.kirsle.net/apps/gophertype/pkg/constants"
	"git.kirsle.net/apps/gophertype/pkg/models"
	"git.kirsle.net/apps/gophertype/pkg/responses"
	"git.kirsle.net/apps/gophertype/pkg/settings"
	"github.com/albrow/forms"
)

// InitialSetup at "/admin/setup"
func InitialSetup(w http.ResponseWriter, r *http.Request) {
	// Template variables.
	v := responses.NewTemplateVars(w, r)
	v.SetupNeeded = false // supress the banner on this page.

	// See if we already have an admin account.
	if _, err := models.Users.FirstAdmin(); err == nil {
		v.Message = "This site is already initialized."
		responses.Forbidden(w, r, "This site has already been initialized.")
		return
	}

	// POST handler: create the admin account.
	for r.Method == http.MethodPost {
		form, err := forms.Parse(r)
		if err != nil {
			responses.Error(w, r, http.StatusBadRequest, err.Error())
			return
		}

		v.FormValues = form.Values

		// Validate form parameters.
		val := form.Validator()
		val.Require("email")
		val.MatchEmail("email")
		val.MinLength("password", 8)
		val.Require("password2")
		val.Equal("password", "password2")
		if val.HasErrors() {
			v.Error = fmt.Errorf("validation error")
			v.ValidationError = val.ErrorMap()
			break
		}

		var (
			email       = form.Get("email")
			displayName = form.Get("name")
			password    = form.Get("password")
			password2   = form.Get("password2")
		)

		// Username and display name validation happens in CreateUser.
		// Validate the passwords match here.
		if len(password) < constants.PasswordMinLength {
			v.Error = fmt.Errorf("your password is too short (must be %d+ characters)", constants.PasswordMinLength)
		}
		if password != password2 {
			v.Error = errors.New("your passwords don't match")
		} else {
			admin := models.User{
				Email:   email,
				Name:    displayName,
				IsAdmin: true,
			}
			admin.SetPassword(password)

			if err := models.Users.CreateUser(admin); err != nil {
				v.Error = err
			} else {
				// Admin created! Make the default config.
				cfg := settings.Load()
				cfg.Initialized = true
				if err := cfg.Save(); err != nil {
					v.Error = err
				} else {
					responses.Redirect(w, r, "/login")
					return
				}
			}
		}

		break
	}

	responses.RenderTemplate(w, r, "_builtin/initial_setup.gohtml", v)
}
