package middleware

import (
	"context"
	"crypto/hmac"
	"crypto/sha256"
	"encoding/base64"
	"encoding/hex"
	"encoding/json"
	"mc-monitor/models"
	"net/http"
	"strings"
)

const sessionSecret = "mc-monitoring-secret"

type ContextKey string

const SessionContextKey ContextKey = "session"

type SessionData struct {
	Username string `json:"username"`
}

func CreateSession(username string) string {
	data := SessionData{Username: username}
	jsonData, _ := json.Marshal(data)
	encoded := base64.StdEncoding.EncodeToString(jsonData)

	signature := createSignature(encoded)
	return encoded + "." + signature
}

func createSignature(data string) string {
	h := hmac.New(sha256.New, []byte(sessionSecret))
	h.Write([]byte(data))
	return hex.EncodeToString(h.Sum(nil))
}

func verifySignature(data, signature string) bool {
	expected := createSignature(data)
	return hmac.Equal([]byte(expected), []byte(signature))
}

func GetSession(r *http.Request) (*SessionData, bool) {
	cookie, err := r.Cookie("session")
	if err != nil {
		return nil, false
	}

	parts := strings.Split(cookie.Value, ".")
	if len(parts) != 2 {
		return nil, false
	}

	encodedData := parts[0]
	signature := parts[1]

	if !verifySignature(encodedData, signature) {
		return nil, false
	}

	data, err := base64.StdEncoding.DecodeString(encodedData)
	if err != nil {
		return nil, false
	}

	var session SessionData
	if err := json.Unmarshal(data, &session); err != nil {
		return nil, false
	}

	return &session, true
}

func AuthRequired(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		session, ok := GetSession(r)
		if !ok {
			http.Redirect(w, r, "/login", http.StatusSeeOther)
			return
		}

		_, exists := models.GetUser(session.Username)
		if !exists {
			http.Redirect(w, r, "/login", http.StatusSeeOther)
			return
		}

		ctx := context.WithValue(r.Context(), SessionContextKey, session)
		next.ServeHTTP(w, r.WithContext(ctx))
	})
}
