package forum

import (
	"net/http"
	"regexp"
	"strconv"

	"code.nonshy.com/nonshy/website/pkg/config"
	"code.nonshy.com/nonshy/website/pkg/log"
	"code.nonshy.com/nonshy/website/pkg/models"
	"code.nonshy.com/nonshy/website/pkg/session"
	"code.nonshy.com/nonshy/website/pkg/templates"
)

var ThreadPathRegexp = regexp.MustCompile(`^/forum/thread/(\d+)$`)

// Thread view for the comment thread body of a forum post.
func Thread() http.HandlerFunc {
	tmpl := templates.Must("forum/thread.html")
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		// Parse the path parameters
		var (
			forum  *models.Forum
			thread *models.Thread
		)

		if m := ThreadPathRegexp.FindStringSubmatch(r.URL.Path); m == nil {
			log.Error("Regexp failed to parse: %s", r.URL.Path)
			templates.NotFoundPage(w, r)
			return
		} else {
			if threadID, err := strconv.Atoi(m[1]); err != nil {
				session.FlashError(w, r, "Invalid thread ID in the address bar.")
				templates.Redirect(w, "/forum")
				return
			} else {
				// Load the thread.
				if found, err := models.GetThread(uint64(threadID)); err != nil {
					session.FlashError(w, r, "That thread does not exist.")
					templates.Redirect(w, "/forum")
					return
				} else {
					thread = found
					forum = &thread.Forum
				}
			}
		}

		// Get the current user.
		currentUser, err := session.CurrentUser(r)
		if err != nil {
			session.FlashError(w, r, "Couldn't get current user: %s", err)
			templates.Redirect(w, "/")
			return
		}

		// Is it an inner circle forum?
		if forum.InnerCircle && !currentUser.IsInnerCircle() {
			templates.NotFoundPage(w, r)
			return
		}

		// Ping the view count on this thread.
		if err := thread.View(currentUser.ID); err != nil {
			log.Error("Couldn't ping view count on thread %d: %s", thread.ID, err)
		}

		// Paginate the comments on this thread.
		var pager = &models.Pagination{
			Page:    1,
			PerPage: config.PageSizeThreadList,
			Sort:    "created_at asc",
		}
		pager.ParsePage(r)

		comments, err := models.PaginateComments(currentUser, "threads", thread.ID, pager)
		if err != nil {
			session.FlashError(w, r, "Couldn't paginate comments: %s", err)
			templates.Redirect(w, "/")
			return
		}

		// Get the like map for these comments.
		commentIDs := []uint64{}
		for _, com := range comments {
			commentIDs = append(commentIDs, com.ID)
		}
		commentLikeMap := models.MapLikes(currentUser, "comments", commentIDs)

		// Get any photo attachments for these comments.
		photos, err := models.MapCommentPhotos(comments)
		if err != nil {
			log.Error("Couldn't MapCommentPhotos: %s", err)
		}

		// Is the current user subscribed to notifications on this thread?
		_, isSubscribed := models.IsSubscribed(currentUser, "threads", thread.ID)

		var vars = map[string]interface{}{
			"Forum":        forum,
			"Thread":       thread,
			"Comments":     comments,
			"LikeMap":      commentLikeMap,
			"PhotoMap":     photos,
			"Pager":        pager,
			"IsSubscribed": isSubscribed,
		}
		if err := tmpl.Execute(w, r, vars); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
	})
}
