package controllers

import (
	"fmt"
	"html/template"
	"net/http"
	"strings"
	"time"

	"git.kirsle.net/apps/gophertype/pkg/authentication"
	"git.kirsle.net/apps/gophertype/pkg/console"
	"git.kirsle.net/apps/gophertype/pkg/mail"
	"git.kirsle.net/apps/gophertype/pkg/markdown"
	"git.kirsle.net/apps/gophertype/pkg/models"
	"git.kirsle.net/apps/gophertype/pkg/responses"
	"git.kirsle.net/apps/gophertype/pkg/session"
	"git.kirsle.net/apps/gophertype/pkg/settings"
	"github.com/albrow/forms"
)

// QuestionHandler implements the "Ask Me Anything" at the URL "/ask"
func QuestionHandler(w http.ResponseWriter, r *http.Request) {
	var (
		v   = responses.NewTemplateVars(w, r)
		ses = session.Get(r)
	)

	// Load their cached name from any previous comments they may have posted.
	name := ses.Name

	q := models.Questions.New()
	q.Name = name

	for r.Method == http.MethodPost {
		form, _ := forms.Parse(r)
		q.ParseForm(r)

		// Validate form parameters.
		val := form.Validator()
		val.Require("question")
		if val.HasErrors() {
			v.ValidationError = val.ErrorMap()
			v.V["Error"] = "Missing required form fields."
			break
		}

		// Cache their name in their session for future comments/asks.
		ses.Name = q.Name
		ses.Save(w)

		// Save the question.
		err := q.Save()
		if err != nil {
			console.Error("Error saving neq eustion: %s", err)
			responses.Error(w, r, http.StatusInternalServerError, "Error saving question: "+err.Error())
			return
		}

		// Email the site admin.
		if name == "" {
			name = "Anonymous"
		}
		subject := fmt.Sprintf("Ask Me Anything (%s) from %s", settings.Current.Title, name)
		go mail.EmailAdmins(mail.Email{
			Subject:  subject,
			Template: "_builtin/email/generic.gohtml",
			Data: map[string]interface{}{
				"Subject": subject,
				"Message": template.HTML(
					markdown.RenderMarkdown(fmt.Sprintf(
						"%s\n\nAnswer this at %s",
						q.Question,
						strings.TrimSuffix(settings.Current.BaseURL, "/")+"/ask",
					)),
				),
			},
		})

		session.Flash(w, r, "Your question has been recorded!")
		responses.Redirect(w, r, "/ask")
		return
	}

	// If logged in, load the pending questions.
	if authentication.LoggedIn(r) {
		pending, err := models.Questions.Pending()
		if err != nil {
			console.Error("Error loading pending questions: %s", err)
		}
		v.V["Pending"] = pending
	}

	// Load the recently answered questions for public users.
	recent, err := models.Questions.RecentlyAnswered(10)
	if err != nil {
		console.Error("Error loading recently answered questions: %s", err)
	}

	v.V["Q"] = q
	v.V["Recent"] = recent
	responses.RenderTemplate(w, r, "_builtin/questions.gohtml", v)
}

// AnswerHandler handles answering (and deleting) questions.
func AnswerHandler(w http.ResponseWriter, r *http.Request) {
	v := responses.NewTemplateVars(w, r)

	CurrentUser, _ := authentication.CurrentUser(r)

	// Validate form parameters.
	form, _ := forms.Parse(r)
	val := form.Validator()
	val.Require("id")
	val.Require("answer")
	val.Require("submit")
	if val.HasErrors() {
		v.ValidationError = val.ErrorMap()
		v.V["Error"] = "Missing required form fields."
		responses.RenderTemplate(w, r, "_builtin/questions.gohtml", v)
		return
	}

	// Look up the question.
	q, err := models.Questions.Load(form.GetInt("id"))
	if err != nil {
		responses.Error(w, r, http.StatusInternalServerError, err.Error())
		return
	}

	// Handle submit actions.
	switch form.Get("submit") {
	case "answer":
		// Prepare a Markdown themed blog post for this answer.
		name := q.Name
		if name == "" {
			name = "Anonymous"
		}

		post := models.Post{
			Title:          "Ask",
			ContentType:    "markdown",
			Privacy:        models.Public,
			EnableComments: true,
			AuthorID:       CurrentUser.ID,
			Tags: []models.TaggedPost{
				models.TaggedPost{Tag: "ask"},
			},
			Fragment: fmt.Sprintf("ask-%s",
				time.Now().Format("20060102150405"),
			),
			Body: fmt.Sprintf(
				"> **%s** asks:\n\n> %s\n\n%s\n",
				name,
				strings.Replace(q.Question, "\n", "\n> ", 0),
				form.Get("answer"),
			),
		}
		post.Save()

		// Associate the question to this post ID.
		q.PostID = post.ID
		q.Answered = true
		q.Save()

		// Send the admin to the post edit page.
		responses.Redirect(w, r, "/"+post.Fragment)
	case "delete":
		q.Delete()
		session.Flash(w, r, "Question deleted!")
		responses.Redirect(w, r, "/ask")
	default:
		responses.BadRequest(w, r, "Invalid submit method.")
	}
}
