package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"path/filepath"
	"strings"

	"github.com/gorilla/mux"
	"github.com/gorilla/sessions"
)

var (
	store = sessions.NewCookieStore([]byte(os.Getenv("SESSION_KEY")))
	toks  = make(map[string]Tokens)
)

func topWrapper(r *http.Request) string {
	defer log.PanicSafe()
	headerTemplate, err := ioutil.ReadFile("./static/header.tpl")
	if err != nil {
		log.LogError(fmt.Sprintf("Unable to open header template: ```%+v```", err))
		return ""
	}
	header := string(headerTemplate)
	login := "Login"
	loggedIn, user := detectUser(r, "topWrapper")
	if loggedIn {
		login = fmt.Sprintf("Logout %s", user)
	}
	header = strings.Replace(header, "$LOGIN", login, -1)
	return header
}

func bodyWrapper(r *http.Request, template string) string {
	defer log.PanicSafe()
	bodyTemplate, err := ioutil.ReadFile(fmt.Sprintf("./static/%+v.tpl", template))
	if err != nil {
		log.LogError(fmt.Sprintf("Attempt to load %s.tpl failed. ```%+v```", template, err))
		return bodyWrapper(r, "404")
	}
	return string(bodyTemplate)

}
func pageBuilder(r *http.Request, pageName string) string {
	defer log.PanicSafe()
	pageCode := topWrapper(r)
	pageCode += bodyWrapper(r, pageName)
	return pageCode
}

func greetUser(w http.ResponseWriter, r *http.Request) {
	defer log.PanicSafe()
	log.LogInfo(fmt.Sprintf("%s called greetUser", getSessionIdentifier(r)))
	loggedIn, _ := detectUser(r, "Homepage")

	if loggedIn {
		bodyTemplate, _ := ioutil.ReadFile("./static/index.html")
		fmt.Fprint(w, string(bodyTemplate))
	} else {
		fmt.Fprint(w, pageBuilder(r, "home"))
	}
}

func passPage(w http.ResponseWriter, r *http.Request) {
	defer log.PanicSafe()
	log.LogInfo(fmt.Sprintf("%s called passPage", getSessionIdentifier(r)))
	fmt.Fprint(w, pageBuilder(r, "pass"))
}
func loginPage(w http.ResponseWriter, r *http.Request) {
	defer log.PanicSafe()
	log.LogInfo(fmt.Sprintf("%s called loginPage", getSessionIdentifier(r)))
	session, err := store.Get(r, "2fa")
	if err != nil {
		log.LogWarn("Unable to open 2fa session in loginpage")
	}
	loggedIn, _ := detectUser(r, "loginPage")
	if loggedIn {
		session.Values["username"] = nil
		err = session.Save(r, w)
		if err != nil {
			log.LogWarn("Error logging out from loginPage()")
		}
		fmt.Fprint(w, pageBuilder(r, "home"))
		return
	}
	fmt.Fprint(w, pageBuilder(r, "login"))
}

func notFoundPage(w http.ResponseWriter, r *http.Request) {
	defer log.PanicSafe()
	go log.LogWarn(fmt.Sprintf("%s triggered notFoundPage", getSessionIdentifier(r)))
	fmt.Fprint(w, topWrapper(r))

	fmt.Fprint(w, card("Oops! That Page Was Not found.",
		"Sorry, a 404 error has occured. The requested page not found! <br><br>"+
			"<iframe width=\"560\" height=\"315\" src=\"https://www.youtube.com/embed/t3otBjVZzT0\" frameborder=\"0\" allow=\"accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen></iframe>",
		"<div class=\"error-actions\"><a href=\"/\" class=\"btn btn-primary btn-lg\"><span class=\"glyphicon glyphicon-home\"></span>Take Me Home </a>  <a href=\"mailto://rudi@nmare.net\" class=\"btn btn-default btn-lg\"><span class=\"glyphicon glyphicon-envelope\"></span> Contact Support </a></div>"))

}
func card(title string, content string, footer string) string {
	defer log.PanicSafe()
	cardTemplate, err := ioutil.ReadFile("./static/card.tpl")
	if err != nil {
		log.LogError("Unable to open card template")
		return ""
	}
	cardString := string(cardTemplate)
	cardString = strings.Replace(cardString, "$TITLE", title, -1)
	cardString = strings.Replace(cardString, "$CONTENT", content, -1)
	cardString = strings.Replace(cardString, "$FOOTER", footer, -1)
	return cardString

}

func getPending(w http.ResponseWriter, r *http.Request) {
	defer log.PanicSafe()
	loggedIn, _ := detectUser(r, "getPending")
	if loggedIn {
		pending, err := json.Marshal(config.Verifications)
		if err != nil {
			log.LogErrorType(err)
			notFoundPage(w, r)
		}
		fmt.Fprint(w, string(pending))
	} else {
		notFoundPage(w, r)
	}
}
func getConfig(w http.ResponseWriter, r *http.Request) {
	defer log.PanicSafe()
	loggedIn, _ := detectUser(r, "getConfig")
	if loggedIn {
		pending, err := json.Marshal(config)
		if err != nil {
			log.LogErrorType(err)
			notFoundPage(w, r)
		}
		fmt.Fprint(w, string(pending))
	} else {
		notFoundPage(w, r)
	}
}
func getProbations(w http.ResponseWriter, r *http.Request) {
	defer log.PanicSafe()
	loggedIn, _ := detectUser(r, "getProbations")
	if loggedIn {
		pending, err := json.Marshal(config.Probations)
		if err != nil {
			log.LogErrorType(err)
			notFoundPage(w, r)
		}
		fmt.Fprint(w, string(pending))
	} else {
		notFoundPage(w, r)
	}
}
func getVerifications(w http.ResponseWriter, r *http.Request) {
	defer log.PanicSafe()
	loggedIn, _ := detectUser(r, "getVerifications")
	if !loggedIn {
		notFoundPage(w, r)
		return
	}
	var files []string
	root := "./verifications/"
	err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
		files = append(files, path)
		return nil
	})
	if err != nil {
		log.LogErrorType(err)
	}
	var v []Verification
	for _, file := range files {
		info := strings.Split(file, "-")
		if len(info) < 2 {
			continue
		}
		var ver Verification
		ver.UserID = strings.Replace(info[0], "verifications/", "", -1)
		ver.Username = info[1]
		ver.Photo = file
		fileStat, _ := os.Stat(file)
		ver.Closed = fileStat.ModTime()
		v = append(v, ver)
	}
	verifications, err := json.Marshal(v)
	if err != nil {
		log.LogErrorType(err)
	}
	fmt.Fprint(w, string(verifications))
}

func getUser(w http.ResponseWriter, r *http.Request) {
	loggedIn, _ := detectUser(r, "getVerifications")
	if !loggedIn {
		notFoundPage(w, r)
		return
	}
	vars := mux.Vars(r)
	username := vars["userID"]
	if len(username) == 0 {
		username = r.FormValue("userID")
	}
	m, err := dg.GuildMember(config.GuildID, username)
	if err != nil {
		log.LogErrorType(err)
	}
	ret, err := json.Marshal(m)
	if err != nil {
		log.LogErrorType(err)
	}
	fmt.Fprint(w, string(ret))
}

func runWeb() {
	defer log.PanicSafe()
	router := mux.NewRouter().StrictSlash(true)
	log.LogInfo("Adding HandleFuncs to router")
	router.NotFoundHandler = http.HandlerFunc(notFoundPage)
	router.HandleFunc("/pass", passPage)
	router.HandleFunc("/login", loginPage)
	router.HandleFunc("/api/login", tryLogin)
	router.HandleFunc("/api/config", getConfig)
	router.HandleFunc("/api/pending", getPending)
	router.HandleFunc("/api/verifications", getVerifications)
	router.HandleFunc("/api/probations", getProbations)
	router.HandleFunc("/api/passreq", reqPass)
	router.HandleFunc("/api/user", getUser)
	router.HandleFunc("/", greetUser)
	router.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir("./static"))))
	router.PathPrefix("/verifications/").Handler(http.StripPrefix("/verifications/", http.FileServer(http.Dir("./verifications"))))
	log.LogInfo("Starting server")
	log.LogErrorType(http.ListenAndServe(":8080", router))
}