// handlers/auth.go
package handlers

import (
	"bytes"
	"encoding/json"
	"io"
	"net/http"
	"strings"
	"time"

	"api_bb/internal/models"
	"api_bb/internal/service"
	"api_bb/pkg/logger"
	"api_bb/pkg/utils"

	"go.uber.org/zap"
)

type AuthHandler struct {
	authService  service.AuthService
	jwtService   service.JWTService
	logger       logger.LoggerInterface
	emailService service.EmailService
}

func NewAuthHandler(authService service.AuthService, jwtService service.JWTService, emailService service.EmailService) *AuthHandler {
	return &AuthHandler{
		authService:  authService,
		jwtService:   jwtService,
		logger:       logger.NewWrapper(logger.Get().With(zap.String("handler", "auth"))),
		emailService: emailService,
	}
}

type RegisterRequest struct {
	Email      string `json:"email"`
	Password   string `json:"password"`
	FirstName  string `json:"firstName"`
	LastName   string `json:"lastName"`
	Phone      string `json:"phone"`
	Experience string `json:"experience"`
	Goals      string `json:"goals"`
	Newsletter bool   `json:"newsletter"`
}

type LoginRequest struct {
	Email    string `json:"email"`
	Password string `json:"password"`
}

func (h *AuthHandler) Register(w http.ResponseWriter, r *http.Request) {

	h.logger.Info("handling register request",
		zap.String("method", r.Method),
		zap.String("path", r.URL.Path),
		zap.String("remote_addr", r.RemoteAddr),
	)

	// Логируем тело запроса для отладки
	bodyBytes, err := io.ReadAll(r.Body)
	if err != nil {
		h.logger.Error("failed to read request body", zap.Error(err))
		utils.RespondWithError(w, http.StatusBadRequest, "Failed to read request body: "+err.Error())
		return
	}

	// Восстанавливаем тело для дальнейшего использования
	r.Body = io.NopCloser(bytes.NewBuffer(bodyBytes))

	h.logger.Debug("raw register request body", zap.String("body", string(bodyBytes)))

	var req RegisterRequest
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		h.logger.Error("failed to decode JSON payload", zap.Error(err))
		utils.RespondWithError(w, http.StatusBadRequest, "Invalid JSON payload: "+err.Error())
		return
	}

	h.logger.Info("parsed register request",
		zap.String("email", req.Email),
		zap.String("first_name", req.FirstName),
		zap.String("last_name", req.LastName),
	)

	// Валидация обязательных полей
	if req.FirstName == "" {
		h.logger.Warn("register failed - first name required")
		utils.RespondWithError(w, http.StatusBadRequest, "First name is required")
		return
	}
	if req.LastName == "" {
		h.logger.Warn("register failed - last name required")
		utils.RespondWithError(w, http.StatusBadRequest, "Last name is required")
		return
	}
	if req.Email == "" {
		h.logger.Warn("register failed - email required")
		utils.RespondWithError(w, http.StatusBadRequest, "Email is required")
		return
	}
	if req.Password == "" {
		h.logger.Warn("register failed - password required")
		utils.RespondWithError(w, http.StatusBadRequest, "Password is required")
		return
	}
	if len(req.Password) < 6 {
		h.logger.Warn("register failed - password too short")
		utils.RespondWithError(w, http.StatusBadRequest, "Password must be at least 6 characters")
		return
	}

	user := &models.User{
		Email:      req.Email,
		Password:   req.Password,
		FirstName:  req.FirstName,
		LastName:   req.LastName,
		Phone:      req.Phone,
		Experience: req.Experience,
		Goals:      req.Goals,
		Newsletter: req.Newsletter,
		Role:       "user",
		CreatedAt:  time.Now(),
		UpdatedAt:  time.Now(),
	}

	if err := h.authService.Register(user); err != nil {
		h.logger.Error("auth service registration failed",
			zap.String("email", req.Email),
			zap.Error(err),
		)
		utils.RespondWithError(w, http.StatusBadRequest, err.Error())
		return
	}

	h.logger.Info("user registered successfully",
		zap.Uint("user_id", user.ID),
		zap.String("email", user.Email),
	)

	// Отправки сообщения для верификации Email
	if err := h.emailService.SendVerificationEmail(user.ID, user.Email, user.FirstName); err != nil {
		h.logger.Error("failed to send verification email",
		zap.Error(err),
		zap.Uint("user_id", user.ID))
	}

	// После успешной регистрации возвращаем данные пользователя
	utils.RespondWithJSON(w, http.StatusCreated, map[string]interface{}{
		"message": "User registered successfully",
		"user":    toUserResponse(user),
	})
}

func (h *AuthHandler) Login(w http.ResponseWriter, r *http.Request) {
	h.logger.Info("handling login request",
		zap.String("method", r.Method),
		zap.String("path", r.URL.Path),
		zap.String("remote_addr", r.RemoteAddr),
	)

	// Проверяем Content-Type
	if r.Header.Get("Content-Type") != "application/json" {
		h.logger.Warn("invalid content type", zap.String("content_type", r.Header.Get("Content-Type")))
		utils.RespondWithError(w, http.StatusBadRequest, "Content-Type must be application/json")
		return
	}

	// Читаем и логируем тело запроса
	bodyBytes, err := io.ReadAll(r.Body)
	if err != nil {
		h.logger.Error("failed to read request body", zap.Error(err))
		utils.RespondWithError(w, http.StatusBadRequest, "Failed to read request body")
		return
	}
	defer r.Body.Close()

	// Восстанавливаем тело
	r.Body = io.NopCloser(bytes.NewBuffer(bodyBytes))

	h.logger.Debug("request body", zap.String("body", string(bodyBytes)))

	var req LoginRequest
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		h.logger.Error("JSON decode failed",
			zap.Error(err),
			zap.String("raw_body", string(bodyBytes)),
		)
		utils.RespondWithError(w, http.StatusBadRequest, "Invalid JSON: "+err.Error())
		return
	}

	req.Email = strings.TrimSpace(req.Email)
	req.Password = strings.TrimSpace(req.Password)

	// Валидация
	if req.Email == "" || req.Password == "" {
		h.logger.Warn("validation failed",
			zap.String("email", req.Email),
			zap.Int("password_len", len(req.Password)),
		)
		utils.RespondWithError(w, http.StatusBadRequest, "Email and password are required")
		return
	}

	h.logger.Info("attempting login", zap.String("email", req.Email))

	user, token, err := h.authService.Login(req.Email, req.Password)
	if err != nil {
		h.logger.Warn("login failed", zap.String("email", req.Email), zap.Error(err))
		utils.RespondWithError(w, http.StatusUnauthorized, err.Error())
		return
	}

	// Устанавливаем куки
	http.SetCookie(w, &http.Cookie{
		Name:     "auth_token",
		Value:    token,
		Path:     "/",
		HttpOnly: true,
		Secure:   false,
		SameSite: http.SameSiteLaxMode,
		Expires:  time.Now().Add(24 * time.Hour),
	})

	h.logger.Info("login successful",
		zap.Uint("user_id", user.ID),
		zap.String("email", user.Email),
	)

	utils.RespondWithJSON(w, http.StatusOK, map[string]interface{}{
		"message": "Login successful",
		"token":   token,
		"user":    toUserResponse(user),
	})
}

func (h *AuthHandler) Logout(w http.ResponseWriter, r *http.Request) {
	// Устанавливаем CORS заголовки
	w.Header().Set("Access-Control-Allow-Origin", r.Header.Get("Origin"))
	w.Header().Set("Access-Control-Allow-Credentials", "true")

	h.logger.Info("handling logout request",
		zap.String("method", r.Method),
		zap.String("path", r.URL.Path),
		zap.String("remote_addr", r.RemoteAddr),
	)

	// Удаляем куку
	http.SetCookie(w, &http.Cookie{
		Name:     "auth_token",
		Value:    "",
		Path:     "/",
		HttpOnly: true,
		Secure:   false,
		SameSite: http.SameSiteLaxMode,
		Expires:  time.Now().Add(-1 * time.Hour),
		MaxAge:   -1,
	})

	h.logger.Info("user logged out successfully")

	utils.RespondWithJSON(w, http.StatusOK, map[string]string{
		"message": "Logout successful",
	})
}
