package handlers

import (
	"net/http"
	"strings"

	"nitipabsen/backend/config"
	authmiddleware "nitipabsen/backend/middleware"
	"nitipabsen/backend/models"

	"golang.org/x/crypto/bcrypt"
)

type AuthHandler struct{}
type authRequest struct {
	Username string `json:"username"`
	Password string `json:"password"`
}

func (AuthHandler) Register(w http.ResponseWriter, r *http.Request) {
	var input authRequest
	if !decode(r, &input) || input.Username == "" || len(input.Password) < 6 {
		writeError(w, http.StatusBadRequest, "username and password (min. 6 characters) are required")
		return
	}
	hash, err := bcrypt.GenerateFromPassword([]byte(input.Password), bcrypt.DefaultCost)
	if err != nil {
		writeError(w, 500, "could not create account")
		return
	}
	user := models.User{Name: input.Username, Username: strings.ToLower(input.Username), PasswordHash: string(hash)}
	if err := config.DB.Create(&user).Error; err != nil {
		writeError(w, http.StatusConflict, "username already registered")
		return
	}
	token, err := authmiddleware.IssueToken(w, user.ID)
	if err != nil {
		writeError(w, 500, "could not create session")
		return
	}
	writeJSON(w, http.StatusCreated, map[string]interface{}{
		"user":  user,
		"token": token,
		"name":  user.Name,
	})
}

func (AuthHandler) Login(w http.ResponseWriter, r *http.Request) {
	var input authRequest
	if !decode(r, &input) {
		writeError(w, 400, "invalid request")
		return
	}
	var user models.User
	if err := config.DB.Where("username = ?", strings.ToLower(input.Username)).First(&user).Error; err != nil || bcrypt.CompareHashAndPassword([]byte(user.PasswordHash), []byte(input.Password)) != nil {
		writeError(w, http.StatusUnauthorized, "username or password is incorrect")
		return
	}
	token, err := authmiddleware.IssueToken(w, user.ID)
	if err != nil {
		writeError(w, 500, "could not create session")
		return
	}
	writeJSON(w, 200, map[string]interface{}{
		"user":  user,
		"token": token,
		"name":  user.Name,
	})
}

func (AuthHandler) Me(w http.ResponseWriter, r *http.Request) {
	userID, authenticated := authmiddleware.UserID(r.Context())
	if !authenticated {
		userID, authenticated = authmiddleware.ParseToken(r)
	}
	if !authenticated {
		writeJSON(w, http.StatusOK, map[string]bool{"authenticated": false})
		return
	}
	var user models.User
	if err := config.DB.First(&user, userID).Error; err != nil {
		writeError(w, 401, "user not found")
		return
	}
	writeJSON(w, 200, map[string]interface{}{"authenticated": true, "user": user})
}

func (AuthHandler) Logout(w http.ResponseWriter, _ *http.Request) {
	authmiddleware.ClearToken(w)
	writeJSON(w, 200, map[string]string{"status": "logged out"})
}
