package view
import (
	"fmt"
	"html/template"
	"io"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"time"
	"github.com/google/uuid"
	"streifling.com/jason/cpolis/cmd/control"
	"streifling.com/jason/cpolis/cmd/model"
)
func ShowHub(c *control.Config, db *model.DB, s *control.CookieStore) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		session, err := s.Get(r, "cookie")
		if err != nil {
			tmpl, err := template.ParseFiles(c.WebDir + "/templates/login.html")
			msg := "Session nicht mehr gültig. Bitte erneut anmelden."
			template.Must(tmpl, err).ExecuteTemplate(w, "page-content", msg)
		}
		tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html")
		template.Must(tmpl, err).ExecuteTemplate(w, "page-content", session.Values["role"].(int))
	}
}
func WriteArticle(c *control.Config, db *model.DB) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		tags, err := db.GetTagList()
		if err != nil {
			log.Println(err)
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		tmpl, err := template.ParseFiles(c.WebDir + "/templates/editor.html")
		template.Must(tmpl, err).ExecuteTemplate(w, "page-content", tags)
	}
}
func SubmitArticle(c *control.Config, db *model.DB, s *control.CookieStore) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		session, err := s.Get(r, "cookie")
		if err != nil {
			tmpl, err := template.ParseFiles(c.WebDir + "/templates/login.html")
			msg := "Session nicht mehr gültig. Bitte erneut anmelden."
			template.Must(tmpl, err).ExecuteTemplate(w, "page-content", msg)
		}
		article := &model.Article{
			Title:       r.PostFormValue("article-title"),
			Description: r.PostFormValue("article-description"),
			Content:     r.PostFormValue("article-content"),
			Published:   false,
			Rejected:    false,
			AuthorID:    session.Values["id"].(int64),
		}
		article.ID, err = db.AddArticle(article)
		if err != nil {
			log.Println(err)
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		r.ParseForm()
		tags := make([]int64, 0)
		for _, tag := range r.Form["tags"] {
			tagID, err := strconv.ParseInt(tag, 10, 64)
			if err != nil {
				log.Println(err)
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}
			tags = append(tags, tagID)
		}
		if err = db.WriteArticleTags(article.ID, tags); err != nil {
			log.Println(err)
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html")
		tmpl = template.Must(tmpl, err)
		tmpl.ExecuteTemplate(w, "page-content", session.Values["role"])
	}
}
func ResubmitArticle(c *control.Config, db *model.DB, s *control.CookieStore) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		id, err := strconv.ParseInt(r.PathValue("id"), 10, 64)
		if err != nil {
			log.Println(err)
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		title := r.PostFormValue("article-title")
		description := r.PostFormValue("article-description")
		content := r.PostFormValue("article-content")
		if err = db.UpdateAttributes(
			&model.Attribute{Table: "articles", ID: id, AttName: "title", Value: title},
			&model.Attribute{Table: "articles", ID: id, AttName: "description", Value: description},
			&model.Attribute{Table: "articles", ID: id, AttName: "content", Value: content},
			&model.Attribute{Table: "articles", ID: id, AttName: "rejected", Value: false},
		); err != nil {
			log.Println(err)
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		r.ParseForm()
		tags := make([]int64, 0)
		for _, tag := range r.Form["tags"] {
			tagID, err := strconv.ParseInt(tag, 10, 64)
			if err != nil {
				log.Println(err)
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}
			tags = append(tags, tagID)
		}
		if err = db.UpdateArticleTags(id, tags); err != nil {
			log.Println(err)
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		session, err := s.Get(r, "cookie")
		if err != nil {
			tmpl, err := template.ParseFiles(c.WebDir + "/templates/login.html")
			msg := "Session nicht mehr gültig. Bitte erneut anmelden."
			template.Must(tmpl, err).ExecuteTemplate(w, "page-content", msg)
		}
		tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html")
		tmpl = template.Must(tmpl, err)
		tmpl.ExecuteTemplate(w, "page-content", session.Values["role"])
	}
}
func ShowUnpublishedArticles(c *control.Config, db *model.DB) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		unpublishedArticles, err := db.GetCertainArticles(false, false)
		if err != nil {
			log.Println(err)
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		tmpl, err := template.ParseFiles(c.WebDir + "/templates/unpublished-articles.html")
		tmpl = template.Must(tmpl, err)
		tmpl.ExecuteTemplate(w, "page-content", unpublishedArticles)
	}
}
func ShowRejectedArticles(c *control.Config, db *model.DB, s *control.CookieStore) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		type htmlData struct {
			MyIDs            map[int64]bool
			RejectedArticles []*model.Article
		}
		data := new(htmlData)
		session, err := s.Get(r, "cookie")
		if err != nil {
			log.Println(err)
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		data.RejectedArticles, err = db.GetCertainArticles(false, true)
		if err != nil {
			log.Println(err)
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		data.MyIDs = make(map[int64]bool)
		for _, article := range data.RejectedArticles {
			if article.AuthorID == session.Values["id"].(int64) {
				data.MyIDs[article.ID] = true
			}
		}
		tmpl, err := template.ParseFiles(c.WebDir + "/templates/rejected-articles.html")
		tmpl = template.Must(tmpl, err)
		tmpl.ExecuteTemplate(w, "page-content", data)
	}
}
func ReviewUnpublishedArticle(c *control.Config, db *model.DB, s *control.CookieStore) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		type htmlData struct {
			Title       string
			Description string
			Content     template.HTML
			Tags        []*model.Tag
			ID          int64
		}
		var err error
		data := new(htmlData)
		data.ID, err = strconv.ParseInt(r.PathValue("id"), 10, 64)
		if err != nil {
			log.Println(err)
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		article, err := db.GetArticle(data.ID)
		if err != nil {
			log.Println(err)
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		data.Title, err = control.ConvertToPlain(article.Title)
		if err != nil {
			log.Println(err)
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		data.Description, err = control.ConvertToPlain(article.Description)
		if err != nil {
			log.Println(err)
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		content, err := control.ConvertToHTML(article.Content)
		if err != nil {
			log.Println(err)
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		data.Content = template.HTML(content)
		data.Tags, err = db.GetArticleTags(data.ID)
		if err != nil {
			log.Println(err)
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		tmpl, err := template.ParseFiles(c.WebDir + "/templates/to-be-published.html")
		tmpl = template.Must(tmpl, err)
		tmpl.ExecuteTemplate(w, "page-content", data)
	}
}
func ReviewRejectedArticle(c *control.Config, db *model.DB, s *control.CookieStore) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		type htmlData struct {
			Selected map[int64]bool
			Article  *model.Article
			Tags     []*model.Tag
		}
		data := new(htmlData)
		id, err := strconv.ParseInt(r.PathValue("id"), 10, 64)
		if err != nil {
			log.Println(err)
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		data.Article, err = db.GetArticle(id)
		if err != nil {
			log.Println(err)
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		data.Tags, err = db.GetTagList()
		if err != nil {
			log.Println(err)
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		selectedTags, err := db.GetArticleTags(id)
		if err != nil {
			log.Println(err)
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		data.Selected = make(map[int64]bool)
		for _, tag := range selectedTags {
			data.Selected[tag.ID] = true
		}
		tmpl, err := template.ParseFiles(c.WebDir + "/templates/rework-article.html")
		tmpl = template.Must(tmpl, err)
		tmpl.ExecuteTemplate(w, "page-content", data)
	}
}
func PublishArticle(c *control.Config, db *model.DB, s *control.CookieStore) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		id, err := strconv.ParseInt(r.PathValue("id"), 10, 64)
		if err != nil {
			log.Println(err)
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		session, err := s.Get(r, "cookie")
		if err != nil {
			tmpl, err := template.ParseFiles(c.WebDir + "/templates/login.html")
			msg := "Session nicht mehr gültig. Bitte erneut anmelden."
			template.Must(tmpl, err).ExecuteTemplate(w, "page-content", msg)
		}
		if err = db.AddArticleToCurrentIssue(id); err != nil {
			log.Println(err)
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		if err = db.UpdateAttributes(
			&model.Attribute{Table: "articles", ID: id, AttName: "published", Value: true},
			&model.Attribute{Table: "articles", ID: id, AttName: "rejected", Value: false},
			&model.Attribute{Table: "articles", ID: id, AttName: "created", Value: time.Now().Format("2006-01-02 15:04:05")},
		); err != nil {
			log.Println(err)
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		feed, err := control.GenerateRSS(db, c.Title, c.Link, c.Description)
		if err != nil {
			log.Println(err)
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		if err = control.SaveRSS(c.RSSFile, feed); err != nil {
			log.Println(err)
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html")
		tmpl = template.Must(tmpl, err)
		tmpl.ExecuteTemplate(w, "page-content", session.Values["role"])
	}
}
func RejectArticle(c *control.Config, db *model.DB, s *control.CookieStore) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		id, err := strconv.ParseInt(r.PathValue("id"), 10, 64)
		if err != nil {
			log.Println(err)
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		session, err := s.Get(r, "cookie")
		if err != nil {
			tmpl, err := template.ParseFiles(c.WebDir + "/templates/login.html")
			msg := "Session nicht mehr gültig. Bitte erneut anmelden."
			template.Must(tmpl, err).ExecuteTemplate(w, "page-content", msg)
		}
		if err = db.UpdateAttributes(
			&model.Attribute{Table: "articles", ID: id, AttName: "rejected", Value: true},
		); err != nil {
			log.Println(err)
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html")
		tmpl = template.Must(tmpl, err)
		tmpl.ExecuteTemplate(w, "page-content", session.Values["role"])
	}
}
func ShowCurrentArticles(c *control.Config, db *model.DB) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		articles, err := db.GetCurrentIssueArticles()
		if err != nil {
			log.Println(err)
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		tmpl, err := template.ParseFiles(c.WebDir + "/templates/current-articles.html")
		template.Must(tmpl, err).ExecuteTemplate(w, "page-content", articles)
	}
}
func UploadImage(c *control.Config) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		file, header, err := r.FormFile("article-image")
		if err != nil {
			log.Println(err)
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		defer file.Close()
		nameStrings := strings.Split(header.Filename, ".")
		extension := "." + nameStrings[len(nameStrings)-1]
		filename := fmt.Sprint(uuid.New(), extension)
		absFilepath, err := filepath.Abs(fmt.Sprint(c.PicsDir, "/", filename))
		if err != nil {
			log.Println(err)
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		img, err := os.Create(absFilepath)
		if err != nil {
			log.Println(err)
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		defer img.Close()
		if _, err = io.Copy(img, file); err != nil {
			log.Println(err)
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		alt := strings.Join(nameStrings[0:len(nameStrings)-1], " ")
		imgMD := fmt.Sprint("")
		tmpl, err := template.ParseFiles(c.WebDir + "/templates/editor.html")
		template.Must(tmpl, err).ExecuteTemplate(w, "editor-images", imgMD)
	}
}