package handler

import (
	"eslogad-be/internal/util"
	"net/http"
	"strings"

	"eslogad-be/internal/constants"
	"eslogad-be/internal/contract"
	"eslogad-be/internal/logger"

	"github.com/gin-gonic/gin"
)

type AuthHandler struct {
	authService AuthService
}

func NewAuthHandler(authService AuthService) *AuthHandler {
	return &AuthHandler{
		authService: authService,
	}
}

func (h *AuthHandler) Login(c *gin.Context) {
	var req contract.LoginRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		logger.FromContext(c.Request.Context()).WithError(err).Error("AuthHandler::Login -> request binding failed")
		h.sendValidationErrorResponse(c, "Invalid request body", constants.MissingFieldErrorCode)
		return
	}

	if strings.TrimSpace(req.Email) == "" {
		logger.FromContext(c.Request.Context()).Error("AuthHandler::Login -> email is required")
		h.sendValidationErrorResponse(c, "Email is required", constants.MissingFieldErrorCode)
		return
	}

	if strings.TrimSpace(req.Password) == "" {
		logger.FromContext(c.Request.Context()).Error("AuthHandler::Login -> password is required")
		h.sendValidationErrorResponse(c, "Password is required", constants.MissingFieldErrorCode)
		return
	}

	loginResponse, err := h.authService.Login(c.Request.Context(), &req)
	if err != nil {
		logger.FromContext(c.Request.Context()).WithError(err).Error("AuthHandler::Login -> Failed to login")
		h.sendErrorResponse(c, err.Error(), http.StatusUnauthorized)
		return
	}

	logger.FromContext(c.Request.Context()).Infof("AuthHandler::Login -> Successfully logged in user = %s", loginResponse.User.Email)

	util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(loginResponse), "AuthHandler::Login")
}

func (h *AuthHandler) Logout(c *gin.Context) {
	token := h.extractTokenFromHeader(c)
	if token == "" {
		logger.FromContext(c.Request.Context()).Error("AuthHandler::Logout -> token is required")
		h.sendErrorResponse(c, "Token is required", http.StatusUnauthorized)
		return
	}

	err := h.authService.Logout(c.Request.Context(), token)
	if err != nil {
		logger.FromContext(c.Request.Context()).WithError(err).Error("AuthHandler::Logout -> Failed to logout")
		h.sendErrorResponse(c, err.Error(), http.StatusUnauthorized)
		return
	}

	logger.FromContext(c.Request.Context()).Info("AuthHandler::Logout -> Successfully logged out")
	c.JSON(http.StatusOK, &contract.SuccessResponse{Message: "Successfully logged out"})
}

func (h *AuthHandler) RefreshToken(c *gin.Context) {
	token := h.extractTokenFromHeader(c)
	if token == "" {
		logger.FromContext(c.Request.Context()).Error("AuthHandler::RefreshToken -> token is required")
		h.sendErrorResponse(c, "Token is required", http.StatusUnauthorized)
		return
	}

	loginResponse, err := h.authService.RefreshToken(c.Request.Context(), token)
	if err != nil {
		logger.FromContext(c.Request.Context()).WithError(err).Error("AuthHandler::RefreshToken -> Failed to refresh token")
		h.sendErrorResponse(c, err.Error(), http.StatusUnauthorized)
		return
	}

	logger.FromContext(c.Request.Context()).Infof("AuthHandler::RefreshToken -> Successfully refreshed token for user = %s", loginResponse.User.Email)
	c.JSON(http.StatusOK, loginResponse)
}

func (h *AuthHandler) ValidateToken(c *gin.Context) {
	token := h.extractTokenFromHeader(c)
	if token == "" {
		logger.FromContext(c.Request.Context()).Error("AuthHandler::ValidateToken -> token is required")
		h.sendErrorResponse(c, "Token is required", http.StatusUnauthorized)
		return
	}

	userResponse, err := h.authService.ValidateToken(token)
	if err != nil {
		logger.FromContext(c.Request.Context()).WithError(err).Error("AuthHandler::ValidateToken -> Failed to validate token")
		h.sendErrorResponse(c, err.Error(), http.StatusUnauthorized)
		return
	}

	logger.FromContext(c.Request.Context()).Infof("AuthHandler::ValidateToken -> Successfully validated token for user = %s", userResponse.Email)
	c.JSON(http.StatusOK, userResponse)
}

func (h *AuthHandler) GetProfile(c *gin.Context) {
	token := h.extractTokenFromHeader(c)
	if token == "" {
		logger.FromContext(c.Request.Context()).Error("AuthHandler::GetProfile -> token is required")
		h.sendErrorResponse(c, "Token is required", http.StatusUnauthorized)
		return
	}

	userResponse, err := h.authService.ValidateToken(token)
	if err != nil {
		logger.FromContext(c.Request.Context()).WithError(err).Error("AuthHandler::GetProfile -> Failed to get profile")
		h.sendErrorResponse(c, err.Error(), http.StatusUnauthorized)
		return
	}

	logger.FromContext(c.Request.Context()).Infof("AuthHandler::GetProfile -> Successfully retrieved profile for user = %s", userResponse.Email)
	c.JSON(http.StatusOK, &contract.SuccessResponse{Data: userResponse, Message: "success get user profile"})
}

func (h *AuthHandler) extractTokenFromHeader(c *gin.Context) string {
	authHeader := c.GetHeader("Authorization")
	if authHeader == "" {
		return ""
	}

	// Expected format: "Bearer <token>"
	parts := strings.Split(authHeader, " ")
	if len(parts) != 2 || parts[0] != "Bearer" {
		return ""
	}

	return parts[1]
}

func (h *AuthHandler) sendErrorResponse(c *gin.Context, message string, statusCode int) {
	errorResponse := &contract.ErrorResponse{
		Error:   "error",
		Message: message,
		Code:    statusCode,
	}
	c.JSON(statusCode, errorResponse)
}

func (h *AuthHandler) sendValidationErrorResponse(c *gin.Context, message string, errorCode string) {
	errorResponse := &contract.ErrorResponse{
		Error:   "validation_error",
		Message: message,
		Code:    http.StatusBadRequest,
		Details: map[string]interface{}{
			"error_code": errorCode,
			"entity":     constants.AuthHandlerEntity,
		},
	}
	c.JSON(http.StatusBadRequest, errorResponse)
}
