// handlers/review_handler.go
package handlers

import (
	"api_bb/internal/models"
	"api_bb/internal/service"
	"api_bb/pkg/logger"
	"api_bb/pkg/middleware"
	"api_bb/pkg/utils"
	"net/http"
	"strconv"

	"github.com/go-chi/chi/v5"
	"go.uber.org/zap"
)

// ReviewHandler обрабатывает HTTP-запросы, связанные с отзывами
type ReviewHandler struct {
	reviewService service.ReviewService  // Сервис для работы с отзывами
	logger        logger.LoggerInterface // Логгер для записи событий
}

// NewReviewHandler создает новый экземпляр ReviewHandler
func NewReviewHandler(reviewService service.ReviewService, logger logger.LoggerInterface) *ReviewHandler {
	return &ReviewHandler{
		reviewService: reviewService,
		logger:        logger,
	}
}

// GetReviews возвращает список отзывов с пагинацией и фильтрацией
func (h *ReviewHandler) GetReviews(w http.ResponseWriter, r *http.Request) {
	page, _ := strconv.Atoi(r.URL.Query().Get("page"))
	limit, _ := strconv.Atoi(r.URL.Query().Get("limit"))
	sortBy := r.URL.Query().Get("sort")
	filter := r.URL.Query().Get("filter")

	if page < 1 {
		page = 1
	}
	if limit < 1 {
		limit = 6
	}

	reviews, totalPages, err := h.reviewService.GetAllReviews(page, limit, sortBy, filter)
	if err != nil {
		h.logger.Error("Failed to get reviews", zap.Error(err))
		utils.RespondWithError(w, http.StatusInternalServerError, "Failed to get reviews")
		return
	}

	response := map[string]interface{}{
		"reviews":      reviews,
		"current_page": page,
		"total_pages":  totalPages,
		"total_items":  len(reviews),
	}

	utils.RespondWithJSON(w, http.StatusOK, response)
}

// GetReviewsStats возвращает статистику отзывов
func (h *ReviewHandler) GetReviewsStats(w http.ResponseWriter, r *http.Request) {
	stats, err := h.reviewService.GetReviewsStats()
	if err != nil {
		h.logger.Error("Failed to get reviews stats", zap.Error(err))
		utils.RespondWithError(w, http.StatusInternalServerError, "Failed to get reviews statistics")
		return
	}

	utils.RespondWithJSON(w, http.StatusOK, stats)
}

// GetMyReviews возвращает отзывы текущего аутентифицированного пользователя
func (h *ReviewHandler) GetMyReviews(w http.ResponseWriter, r *http.Request) {
	// Получаем ID пользователя из контекста (добавляется middleware аутентификации)
	userID, ok := r.Context().Value("middleware.UserIDKey").(uint)
	if !ok {
		h.logger.Warn("Failed to get userID from context in GetMyReviews",
			zap.String("path", r.URL.Path),
			zap.String("method", r.Method),
			zap.String("remote_addr", r.RemoteAddr),
		)
		utils.RespondWithError(w, http.StatusUnauthorized, "User not authenticated")
		return
	}

	// Получаем отзывы пользователя из сервиса
	reviews, err := h.reviewService.GetUserReviews(userID)
	if err != nil {
		h.logger.With(zap.Int("userID", int(userID))).Error("Failed to get user reviews", zap.Error(err))
		utils.RespondWithError(w, http.StatusInternalServerError, "Failed to get your reviews")
		return
	}

	utils.RespondWithJSON(w, http.StatusOK, reviews)
}

// CreateReview создает новый отзыв от имени текущего пользователя
func (h *ReviewHandler) CreateReview(w http.ResponseWriter, r *http.Request) {
	// Получаем ID пользователя из контекста
	userID, ok := r.Context().Value(middleware.UserIDKey).(uint)
	if !ok {
		h.logger.Warn("Failed to get userID from context in CreateReview",
			zap.String("path", r.URL.Path),
			zap.String("method", r.Method),
			zap.String("remote_addr", r.RemoteAddr),
			zap.Uint("userID", userID),
		)
		utils.RespondWithError(w, http.StatusUnauthorized, "User not authenticated")
		return
	}

	h.logger.Debug("Successfully extracted userID from context",
		zap.Uint("userID", userID),
		zap.String("path", r.URL.Path),
		zap.String("method", r.Method),
	)

	// Декодируем тело запроса
	var req models.CreateReviewRequest
	if err := utils.DecodeJSONBody(w, r, &req); err != nil {
		h.logger.Error("Failed to decode review request",
			zap.Error(err),
			zap.Uint("userID", userID),
		)
		utils.RespondWithError(w, http.StatusBadRequest, "Invalid request body")
		return
	}

	// Создаем отзыв через сервис
	review, err := h.reviewService.CreateReview(&req, userID)
	if err != nil {
		h.logger.With(zap.Int("userID", int(userID))).Error("Failed to create review", zap.Error(err))
		utils.RespondWithError(w, http.StatusInternalServerError, "Failed to create review")
		return
	}

	h.logger.Info("Review created successfully",
		zap.Uint("userID", userID),
		zap.Any("review_id", review.ID),
	)

	utils.RespondWithJSON(w, http.StatusCreated, review)
}

// GetReviewByID возвращает отзыв по его идентификатору
func (h *ReviewHandler) GetReviewByID(w http.ResponseWriter, r *http.Request) {
	// Получаем ID отзыва из параметров URL
	idStr := chi.URLParam(r, "id")
	id, err := strconv.ParseUint(idStr, 10, 32)
	if err != nil {
		utils.RespondWithError(w, http.StatusBadRequest, "Invalid review ID")
		return
	}

	// Получаем отзыв из сервиса
	review, err := h.reviewService.GetReviewByID(uint(id))
	if err != nil {
		h.logger.With(zap.Int("id", int(id))).Error("Failed to get review", zap.Error(err))
		utils.RespondWithError(w, http.StatusNotFound, "Review not found")
		return
	}

	utils.RespondWithJSON(w, http.StatusOK, review)
}

// UpdateReview обновляет существующий отзыв
func (h *ReviewHandler) UpdateReview(w http.ResponseWriter, r *http.Request) {
	// Получаем ID пользователя из контекста
	userID, ok := r.Context().Value(middleware.UserIDKey).(uint)
	if !ok {
		h.logger.Warn("Failed to get userID from context in UpdateReview",
			zap.String("path", r.URL.Path),
			zap.String("method", r.Method),
			zap.String("remote_addr", r.RemoteAddr),
			zap.Uint("userID", userID),
		)
		utils.RespondWithError(w, http.StatusUnauthorized, "User not authenticated")
		return
	}

	// Получаем флаг администратора из контекста
	isAdmin, _ := r.Context().Value("IsAdmin").(bool)

	// Получаем ID отзыва из параметров URL
	idStr := chi.URLParam(r, "id")
	id, err := strconv.ParseUint(idStr, 10, 32)
	if err != nil {
		utils.RespondWithError(w, http.StatusBadRequest, "Invalid review ID")
		return
	}

	// Декодируем тело запроса
	var req models.UpdateReviewRequest
	if err := utils.DecodeJSONBody(w, r, &req); err != nil {
		h.logger.Error("Failed to decode update review request",
			zap.Error(err),
			zap.Uint("userID", userID),
			zap.Uint("review_id", uint(id)),
		)
		utils.RespondWithError(w, http.StatusBadRequest, "Invalid request body")
		return
	}

	// Обновляем отзыв через сервис
	review, err := h.reviewService.UpdateReview(uint(id), &req, userID, isAdmin)
	if err != nil {
		h.logger.With(zap.Int("id", int(id))).With(zap.Int("userID", int(userID))).Error("Failed to update review", zap.Error(err))
		if err.Error() == "unauthorized" {
			utils.RespondWithError(w, http.StatusForbidden, "You can only update your own reviews")
			return
		}
		utils.RespondWithError(w, http.StatusInternalServerError, "Failed to update review")
		return
	}

	h.logger.Info("Review updated successfully",
		zap.Uint("userID", userID),
		zap.Uint("review_id", uint(id)),
	)

	utils.RespondWithJSON(w, http.StatusOK, review)
}

// DeleteReview удаляет отзыв
func (h *ReviewHandler) DeleteReview(w http.ResponseWriter, r *http.Request) {
	// Получаем ID пользователя из контекста
	userID, ok := r.Context().Value(middleware.UserIDKey).(uint)
	if !ok {
		h.logger.Warn("Failed to get userID from context in DeleteReview",
			zap.String("path", r.URL.Path),
			zap.String("method", r.Method),
			zap.String("remote_addr", r.RemoteAddr),
		)
		utils.RespondWithError(w, http.StatusUnauthorized, "User not authenticated")
		return
	}

	// Получаем флаг администратора из контекста
	isAdmin, _ := r.Context().Value("IsAdmin").(bool)

	// Получаем ID отзыва из параметров URL
	idStr := chi.URLParam(r, "id")
	id, err := strconv.ParseUint(idStr, 10, 32)
	if err != nil {
		utils.RespondWithError(w, http.StatusBadRequest, "Invalid review ID")
		return
	}

	// Удаляем отзыв через сервис
	err = h.reviewService.DeleteReview(uint(id), userID, isAdmin)
	if err != nil {
		h.logger.With(zap.Int("id", int(id))).With(zap.Int("userID", int(userID))).Error("Failed to delete review", zap.Error(err))
		if err.Error() == "unauthorized" {
			utils.RespondWithError(w, http.StatusForbidden, "You can only delete your own reviews")
			return
		}
		utils.RespondWithError(w, http.StatusInternalServerError, "Failed to delete review")
		return
	}

	h.logger.Info("Review deleted successfully",
		zap.Uint("userID", userID),
		zap.Uint("review_id", uint(id)),
	)

	utils.RespondWithJSON(w, http.StatusOK, map[string]string{"message": "Review deleted successfully"})
}
