// handlers/user_workout_handler.go
package handlers

import (
	"encoding/json"
	"net/http"
	"strconv"

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

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

type UserWorkoutHandler struct {
	logger         logger.LoggerInterface
	workoutService service.WorkoutService
}

func NewUserWorkoutHandler(workoutService service.WorkoutService) *UserWorkoutHandler {
	return &UserWorkoutHandler{
		logger:         logger.NewWrapper(logger.Get().With(zap.String("handler", "user_workout"))),
		workoutService: workoutService,
	}
}

// CreateWorkout создает новую тренировку
func (h *UserWorkoutHandler) CreateWorkout(w http.ResponseWriter, r *http.Request) {
	h.logger.Info("handling create workout request",
		zap.String("method", r.Method),
		zap.String("path", r.URL.Path),
		zap.String("remote_addr", r.RemoteAddr),
	)

	// Получаем пользователя из контекста
	user, ok := middleware.GetUserFromContext(r.Context())
	if !ok {
		h.logger.Warn("create workout failed - authentication required")
		utils.RespondWithError(w, http.StatusUnauthorized, "Authentication required")
		return
	}

	var req models.WorkoutCreateRequest
	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 request payload: "+err.Error())
		return
	}

	// Валидация
	if err := utils.ValidateStruct(req); err != nil {
		h.logger.Warn("create workout failed - validation error", zap.Error(err))
		utils.RespondWithError(w, http.StatusBadRequest, "Validation error: "+err.Error())
		return
	}

	h.logger.Info("creating new workout",
		zap.Uint("user_id", user.ID),
		zap.String("type", string(req.Type)),
		zap.Float64("distance", req.Distance),
		zap.Int("duration", req.Duration),
	)

	// Создаем тренировку
	workout, err := h.workoutService.CreateWorkout(user.ID, &req)
	if err != nil {
		h.logger.Error("failed to create workout in service",
			zap.Uint("user_id", user.ID),
			zap.Error(err),
		)
		utils.RespondWithError(w, http.StatusInternalServerError, "Failed to create workout: "+err.Error())
		return
	}

	h.logger.Info("workout created successfully",
		zap.Uint("workout_id", workout.ID),
		zap.Uint("user_id", user.ID),
	)

	utils.RespondWithJSON(w, http.StatusCreated, map[string]interface{}{
		"message":  "Workout created successfully",
		"workout": workout,
	})
}

// GetWorkouts возвращает список тренировок пользователя
func (h *UserWorkoutHandler) GetWorkouts(w http.ResponseWriter, r *http.Request) {
	h.logger.Info("handling get workouts request",
		zap.String("method", r.Method),
		zap.String("path", r.URL.Path),
		zap.String("remote_addr", r.RemoteAddr),
	)

	// Получаем пользователя из контекста
	user, ok := middleware.GetUserFromContext(r.Context())
	if !ok {
		h.logger.Warn("get workouts failed - authentication required")
		utils.RespondWithError(w, http.StatusUnauthorized, "Authentication required")
		return
	}

	workouts, err := h.workoutService.GetUserWorkouts(user.ID)
	if err != nil {
		h.logger.Error("failed to get user workouts from service",
			zap.Uint("user_id", user.ID),
			zap.Error(err),
		)
		utils.RespondWithError(w, http.StatusInternalServerError, "Failed to get workouts: "+err.Error())
		return
	}

	h.logger.Info("user workouts retrieved successfully",
		zap.Uint("user_id", user.ID),
		zap.Int("workouts_count", len(workouts)),
	)

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

// GetWorkoutByID возвращает тренировку по ID
func (h *UserWorkoutHandler) GetWorkoutByID(w http.ResponseWriter, r *http.Request) {
	h.logger.Info("handling get workout by ID request",
		zap.String("method", r.Method),
		zap.String("path", r.URL.Path),
		zap.String("remote_addr", r.RemoteAddr),
	)

	// Получаем пользователя из контекста
	user, ok := middleware.GetUserFromContext(r.Context())
	if !ok {
		h.logger.Warn("get workout failed - authentication required")
		utils.RespondWithError(w, http.StatusUnauthorized, "Authentication required")
		return
	}

	// Получаем ID тренировки из URL параметров
	workoutIDStr := chi.URLParam(r, "id")
	workoutID, err := strconv.ParseUint(workoutIDStr, 10, 32)
	if err != nil {
		h.logger.Warn("invalid workout ID", zap.String("workout_id", workoutIDStr))
		utils.RespondWithError(w, http.StatusBadRequest, "Invalid workout ID")
		return
	}

	workout, err := h.workoutService.GetWorkoutByID(user.ID, uint(workoutID))
	if err != nil {
		h.logger.Error("failed to get workout from service",
			zap.Uint("user_id", user.ID),
			zap.Uint("workout_id", uint(workoutID)),
			zap.Error(err),
		)
		utils.RespondWithError(w, http.StatusNotFound, "Workout not found: "+err.Error())
		return
	}

	h.logger.Info("workout retrieved successfully",
		zap.Uint("user_id", user.ID),
		zap.Uint("workout_id", uint(workoutID)),
	)

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

// UpdateWorkout обновляет тренировку
func (h *UserWorkoutHandler) UpdateWorkout(w http.ResponseWriter, r *http.Request) {
	h.logger.Info("handling update workout request",
		zap.String("method", r.Method),
		zap.String("path", r.URL.Path),
		zap.String("remote_addr", r.RemoteAddr),
	)

	// Получаем пользователя из контекста
	user, ok := middleware.GetUserFromContext(r.Context())
	if !ok {
		h.logger.Warn("update workout failed - authentication required")
		utils.RespondWithError(w, http.StatusUnauthorized, "Authentication required")
		return
	}

	// Получаем ID тренировки из URL параметров
	workoutIDStr := chi.URLParam(r, "id")
	workoutID, err := strconv.ParseUint(workoutIDStr, 10, 32)
	if err != nil {
		h.logger.Warn("invalid workout ID", zap.String("workout_id", workoutIDStr))
		utils.RespondWithError(w, http.StatusBadRequest, "Invalid workout ID")
		return
	}

	var req models.WorkoutUpdateRequest
	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 request payload: "+err.Error())
		return
	}

	// Валидация
	if err := utils.ValidateStruct(req); err != nil {
		h.logger.Warn("update workout failed - validation error", zap.Error(err))
		utils.RespondWithError(w, http.StatusBadRequest, "Validation error: "+err.Error())
		return
	}

	h.logger.Info("updating workout",
		zap.Uint("user_id", user.ID),
		zap.Uint("workout_id", uint(workoutID)),
		zap.String("type", string(req.Type)),
	)

	// Обновляем тренировку
	workout, err := h.workoutService.UpdateWorkout(user.ID, uint(workoutID), &req)
	if err != nil {
		h.logger.Error("failed to update workout in service",
			zap.Uint("user_id", user.ID),
			zap.Uint("workout_id", uint(workoutID)),
			zap.Error(err),
		)
		utils.RespondWithError(w, http.StatusInternalServerError, "Failed to update workout: "+err.Error())
		return
	}

	h.logger.Info("workout updated successfully",
		zap.Uint("user_id", user.ID),
		zap.Uint("workout_id", uint(workoutID)),
	)

	utils.RespondWithJSON(w, http.StatusOK, map[string]interface{}{
		"message":  "Workout updated successfully",
		"workout": workout,
	})
}

// DeleteWorkout удаляет тренировку
func (h *UserWorkoutHandler) DeleteWorkout(w http.ResponseWriter, r *http.Request) {
	h.logger.Info("handling delete workout request",
		zap.String("method", r.Method),
		zap.String("path", r.URL.Path),
		zap.String("remote_addr", r.RemoteAddr),
	)

	// Получаем пользователя из контекста
	user, ok := middleware.GetUserFromContext(r.Context())
	if !ok {
		h.logger.Warn("delete workout failed - authentication required")
		utils.RespondWithError(w, http.StatusUnauthorized, "Authentication required")
		return
	}

	// Получаем ID тренировки из URL параметров
	workoutIDStr := chi.URLParam(r, "id")
	workoutID, err := strconv.ParseUint(workoutIDStr, 10, 32)
	if err != nil {
		h.logger.Warn("invalid workout ID", zap.String("workout_id", workoutIDStr))
		utils.RespondWithError(w, http.StatusBadRequest, "Invalid workout ID")
		return
	}

	h.logger.Info("deleting workout",
		zap.Uint("user_id", user.ID),
		zap.Uint("workout_id", uint(workoutID)),
	)

	// Удаляем тренировку
	if err := h.workoutService.DeleteWorkout(user.ID, uint(workoutID)); err != nil {
		h.logger.Error("failed to delete workout in service",
			zap.Uint("user_id", user.ID),
			zap.Uint("workout_id", uint(workoutID)),
			zap.Error(err),
		)
		utils.RespondWithError(w, http.StatusInternalServerError, "Failed to delete workout: "+err.Error())
		return
	}

	h.logger.Info("workout deleted successfully",
		zap.Uint("user_id", user.ID),
		zap.Uint("workout_id", uint(workoutID)),
	)

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

// GetWorkoutStats возвращает статистику тренировок
func (h *UserWorkoutHandler) GetWorkoutStats(w http.ResponseWriter, r *http.Request) {
	h.logger.Info("handling get workout stats request",
		zap.String("method", r.Method),
		zap.String("path", r.URL.Path),
		zap.String("remote_addr", r.RemoteAddr),
	)

	// Получаем пользователя из контекста
	user, ok := middleware.GetUserFromContext(r.Context())
	if !ok {
		h.logger.Warn("get workout stats failed - authentication required")
		utils.RespondWithError(w, http.StatusUnauthorized, "Authentication required")
		return
	}

	stats, err := h.workoutService.GetWorkoutStats(user.ID)
	if err != nil {
		h.logger.Error("failed to get workout stats from service",
			zap.Uint("user_id", user.ID),
			zap.Error(err),
		)
		utils.RespondWithError(w, http.StatusInternalServerError, "Failed to get workout stats: "+err.Error())
		return
	}

	h.logger.Info("workout stats retrieved successfully",
		zap.Uint("user_id", user.ID),
		zap.Int("total_workouts", stats.TotalWorkouts),
		zap.Float64("total_distance", stats.TotalDistance),
	)

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

// GetWorkoutsByType возвращает тренировки по типу
func (h *UserWorkoutHandler) GetWorkoutsByType(w http.ResponseWriter, r *http.Request) {
	h.logger.Info("handling get workouts by type request",
		zap.String("method", r.Method),
		zap.String("path", r.URL.Path),
		zap.String("remote_addr", r.RemoteAddr),
	)

	// Получаем пользователя из контекста
	user, ok := middleware.GetUserFromContext(r.Context())
	if !ok {
		h.logger.Warn("get workouts by type failed - authentication required")
		utils.RespondWithError(w, http.StatusUnauthorized, "Authentication required")
		return
	}

	// Получаем тип тренировки из URL параметров
	workoutType := models.WorkoutType(chi.URLParam(r, "type"))
	
	// Валидация типа тренировки
	validTypes := map[models.WorkoutType]bool{
		models.WorkoutTypeEasy:     true,
		models.WorkoutTypeTempo:    true,
		models.WorkoutTypeInterval: true,
		models.WorkoutTypeLong:     true,
		models.WorkoutTypeRecovery: true,
	}
	
	if !validTypes[workoutType] {
		h.logger.Warn("invalid workout type", zap.String("type", string(workoutType)))
		utils.RespondWithError(w, http.StatusBadRequest, "Invalid workout type")
		return
	}

	workouts, err := h.workoutService.GetWorkoutsByType(user.ID, workoutType)
	if err != nil {
		h.logger.Error("failed to get workouts by type from service",
			zap.Uint("user_id", user.ID),
			zap.String("type", string(workoutType)),
			zap.Error(err),
		)
		utils.RespondWithError(w, http.StatusInternalServerError, "Failed to get workouts: "+err.Error())
		return
	}

	h.logger.Info("workouts by type retrieved successfully",
		zap.Uint("user_id", user.ID),
		zap.String("type", string(workoutType)),
		zap.Int("workouts_count", len(workouts)),
	)

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