package handlers

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

	jwt "github.com/dgrijalva/jwt-go"
	"gogs.carducci-dante.gov.it/karmen/core/config"
	"gogs.carducci-dante.gov.it/karmen/core/renderer"
)

func logoutHandler() http.Handler {
	fn := func(w http.ResponseWriter, r *http.Request) {
		session, err := store.Get(r, "login-session")
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		session.Values["token"] = []uint8{}
		session.Save(r, w)

		http.Redirect(w, r, "/", http.StatusSeeOther)

	}
	return http.HandlerFunc(fn)
}

func loginHandler() http.Handler {
	fn := func(w http.ResponseWriter, r *http.Request) {
		if r.Method == "GET" {
			renderer.Render["html"](w, r, nil, r.URL.Query())
		}
		if r.Method == "POST" {
			r.ParseForm()
			token, err := getToken(r.FormValue("username"), r.FormValue("password"))
			if err != nil {
				http.Redirect(w, r, "/login?tpl_layout=login&tpl_content=login&failed=true", http.StatusSeeOther)
			} else {
				session, err := store.Get(r, "login-session")
				if err != nil {
					panic(err)
				}

				session.Values["token"] = token
				session.Save(r, w)
				r.Method = "GET"
				http.Redirect(w, r, "/teachers?format=html&tpl_layout=base&tpl_content=teachers", http.StatusSeeOther)
			}
		}
	}
	return http.HandlerFunc(fn)
}

func checkCredential(username string, password string) (*User, error) {
	if username == config.Config.Admin.Username && password == config.Config.Admin.Password {
		return &User{username, true}, nil
	}
	return nil, errors.New("Authentication failed!")
}

func getToken(username string, password string) ([]byte, error) {
	user, err := checkCredential(username, password)

	if err != nil {
		return nil, err
	}

	/* Set token claims */
	claims := make(map[string]interface{})
	claims["admin"] = user.Admin
	claims["name"] = user.Name
	claims["exp"] = time.Now().Add(time.Hour * 24).Unix()

	/* Create the token */
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims(claims))

	/* Sign the token with our secret */
	tokenString, err := token.SignedString(signingKey)
	if err != nil {
		return nil, err
	}

	return []byte(tokenString), nil
}

func tokenHandler() http.Handler {
	fn := func(w http.ResponseWriter, r *http.Request) {
		username, password, _ := r.BasicAuth()

		user, err := checkCredential(username, password)
		if err != nil {
			panic(err)
		}

		/* Set token claims */
		claims := make(map[string]interface{})
		claims["admin"] = true
		claims["name"] = user.Name
		claims["exp"] = time.Now().Add(time.Hour * 24).Unix()

		/* Create the token */
		token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims(claims))

		/* Sign the token with our secret */
		tokenString, err := token.SignedString(signingKey)
		if err != nil {
			panic(err)
		}

		w.Header().Set("Content-Type", "application/json; charset=utf-8")
		w.Write([]byte(fmt.Sprintf("{\"Token\":\"%s\",\"User\":\"%s\"}", tokenString, user.Name)))
	}
	return http.HandlerFunc(fn)
}
