// handlers/event_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"
	"encoding/json"
	"net/http"
	"strconv"
	"time"

	"go.uber.org/zap"
)

type EventHandler struct {
	logger       logger.LoggerInterface
	eventService service.EventService
}

func NewEventHandler(eventService service.EventService) *EventHandler {
	return &EventHandler{
		logger:       logger.NewWrapper(logger.Get().With(zap.String("handler", "event"))),
		eventService: eventService,
	}
}

// CreateEventRequest - DTO для создания события
type CreateEventRequest struct {
	Title            string           `json:"title" validate:"required,min=5,max=255"`
	Description      string           `json:"description" validate:"required,min=10"`
	Date             time.Time        `json:"date" validate:"required"`
	Location         string           `json:"location" validate:"required,max=255"`
	Type             models.EventType `json:"type" validate:"required,oneof=race training social workshop"`
	Distance         string           `json:"distance" validate:"max=50"`
	MaxParticipants  int              `json:"max_participants" validate:"min=0"`
	RegistrationOpen bool             `json:"registration_open"`
	Image            string           `json:"image" validate:"max=500"`
}

// UpdateEventRequest - DTO для обновления события
type UpdateEventRequest struct {
	Title            string           `json:"title" validate:"required,min=5,max=255"`
	Description      string           `json:"description" validate:"required,min=10"`
	Date             time.Time        `json:"date" validate:"required"`
	Location         string           `json:"location" validate:"required,max=255"`
	Type             models.EventType `json:"type" validate:"required,oneof=race training social workshop"`
	Distance         string           `json:"distance" validate:"max=50"`
	MaxParticipants  int              `json:"max_participants" validate:"min=0"`
	RegistrationOpen bool             `json:"registration_open"`
	Image            string           `json:"image" validate:"max=500"`
}

// EventResponse - DTO для ответа с событием
type EventResponse struct {
	ID                uint             `json:"id"`
	Title             string           `json:"title"`
	Description       string           `json:"description"`
	Date              time.Time        `json:"date"`
	Location          string           `json:"location"`
	Type              models.EventType `json:"type"`
	Distance          string           `json:"distance"`
	ParticipantsCount int              `json:"participants_count"`
	MaxParticipants   int              `json:"max_participants"`
	RegistrationOpen  bool             `json:"registration_open"`
	Image             string           `json:"image"`
	CreatedAt         time.Time        `json:"created_at"`
	UpdatedAt         time.Time        `json:"updated_at"`
}

// CreateEvent создает новое событие
func (h *EventHandler) CreateEvent(w http.ResponseWriter, r *http.Request) {
	h.logger.Info("handling create event 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 event failed - authentication required")
		utils.RespondWithError(w, http.StatusUnauthorized, "Authentication required")
		return
	}

	// Проверяем права доступа (только админы могут создавать события)
	if user.Role != "admin" {
		h.logger.Warn("create event failed - insufficient permissions",
			zap.Uint("user_id", user.ID),
			zap.String("user_role", user.Role),
		)
		utils.RespondWithError(w, http.StatusForbidden, "Insufficient permissions")
		return
	}

	var req CreateEventRequest
	if err := utils.DecodeJSONBody(w, r, &req); err != nil {
		h.logger.Error("failed to decode request body", zap.Error(err))
		utils.RespondWithError(w, http.StatusBadRequest, "Invalid request payload: "+err.Error())
		return
	}

	// Валидация
	if err := utils.ValidateStruct(req); err != nil {
		h.logger.Warn("validation failed for create event", zap.Error(err))
		utils.RespondWithValidationError(w, err)
		return
	}

	// Создаем модель события
	event := &models.Event{
		Title:            req.Title,
		Description:      req.Description,
		Date:             req.Date,
		Location:         req.Location,
		Type:             req.Type,
		Distance:         req.Distance,
		MaxParticipants:  req.MaxParticipants,
		RegistrationOpen: req.RegistrationOpen,
		Image:            req.Image,
	}

	if err := h.eventService.CreateEvent(event); err != nil {
		h.logger.Error("failed to create event", zap.Error(err))
		utils.RespondWithError(w, http.StatusInternalServerError, "Failed to create event: "+err.Error())
		return
	}

	h.logger.Info("event created successfully",
		zap.Uint("event_id", event.ID),
		zap.String("title", event.Title),
	)

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

// GetEvent возвращает событие по ID
func (h *EventHandler) GetEvent(w http.ResponseWriter, r *http.Request) {
	h.logger.Info("handling get event request",
		zap.String("method", r.Method),
		zap.String("path", r.URL.Path),
		zap.String("remote_addr", r.RemoteAddr),
	)

	// Извлекаем ID события из URL параметров
	eventID, err := strconv.ParseUint(r.PathValue("id"), 10, 32)
	if err != nil {
		h.logger.Warn("invalid event ID", zap.Error(err))
		utils.RespondWithError(w, http.StatusBadRequest, "Invalid event ID")
		return
	}

	event, err := h.eventService.GetEventByID(uint(eventID))
	if err != nil {
		h.logger.Warn("event not found",
			zap.Uint("event_id", uint(eventID)),
			zap.Error(err),
		)
		utils.RespondWithError(w, http.StatusNotFound, "Event not found")
		return
	}

	h.logger.Info("event retrieved successfully",
		zap.Uint("event_id", uint(eventID)),
		zap.String("title", event.Title),
	)

	utils.RespondWithJSON(w, http.StatusOK, toEventResponse(event))
}

// GetAllEvents возвращает все события
func (h *EventHandler) GetAllEvents(w http.ResponseWriter, r *http.Request) {
	h.logger.Info("handling get all events request",
		zap.String("method", r.Method),
		zap.String("path", r.URL.Path),
		zap.String("remote_addr", r.RemoteAddr),
	)

	events, err := h.eventService.GetAllEvents()
	if err != nil {
		h.logger.Error("failed to get events", zap.Error(err))
		utils.RespondWithError(w, http.StatusInternalServerError, "Failed to get events: "+err.Error())
		return
	}

	// Преобразуем в response формат
	var eventResponses []EventResponse
	for _, event := range events {
		eventResponses = append(eventResponses, toEventResponse(&event))
	}

	h.logger.Info("events list retrieved successfully",
		zap.Int("events_count", len(eventResponses)),
	)

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

// UpdateEvent обновляет событие
func (h *EventHandler) UpdateEvent(w http.ResponseWriter, r *http.Request) {
	h.logger.Info("handling update event 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 event failed - authentication required")
		utils.RespondWithError(w, http.StatusUnauthorized, "Authentication required")
		return
	}

	if user.Role != "admin" {
		h.logger.Warn("update event failed - insufficient permissions",
			zap.Uint("user_id", user.ID),
			zap.String("user_role", user.Role),
		)
		utils.RespondWithError(w, http.StatusForbidden, "Insufficient permissions")
		return
	}

	// Извлекаем ID события
	eventID, err := strconv.ParseUint(r.PathValue("id"), 10, 32)
	if err != nil {
		h.logger.Warn("invalid event ID", zap.Error(err))
		utils.RespondWithError(w, http.StatusBadRequest, "Invalid event ID")
		return
	}

	var req UpdateEventRequest
	if err := utils.DecodeJSONBody(w, r, &req); err != nil {
		h.logger.Error("failed to decode request body", zap.Error(err))
		utils.RespondWithError(w, http.StatusBadRequest, "Invalid request payload: "+err.Error())
		return
	}

	// Валидация
	if err := utils.ValidateStruct(req); err != nil {
		h.logger.Warn("validation failed for update event", zap.Error(err))
		utils.RespondWithValidationError(w, err)
		return
	}

	// Создаем модель события для обновления
	event := &models.Event{
		ID:               uint(eventID),
		Title:            req.Title,
		Description:      req.Description,
		Date:             req.Date,
		Location:         req.Location,
		Type:             req.Type,
		Distance:         req.Distance,
		MaxParticipants:  req.MaxParticipants,
		RegistrationOpen: req.RegistrationOpen,
		Image:            req.Image,
	}

	if err := h.eventService.UpdateEvent(event); err != nil {
		h.logger.Error("failed to update event",
			zap.Uint("event_id", uint(eventID)),
			zap.Error(err),
		)
		utils.RespondWithError(w, http.StatusInternalServerError, "Failed to update event: "+err.Error())
		return
	}

	h.logger.Info("event updated successfully",
		zap.Uint("event_id", uint(eventID)),
		zap.String("title", event.Title),
	)

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

// DeleteEvent удаляет событие
func (h *EventHandler) DeleteEvent(w http.ResponseWriter, r *http.Request) {
	h.logger.Info("handling delete event 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 event failed - authentication required")
		utils.RespondWithError(w, http.StatusUnauthorized, "Authentication required")
		return
	}

	if user.Role != "admin" {
		h.logger.Warn("delete event failed - insufficient permissions",
			zap.Uint("user_id", user.ID),
			zap.String("user_role", user.Role),
		)
		utils.RespondWithError(w, http.StatusForbidden, "Insufficient permissions")
		return
	}

	// Извлекаем ID события
	eventID, err := strconv.ParseUint(r.PathValue("id"), 10, 32)
	if err != nil {
		h.logger.Warn("invalid event ID", zap.Error(err))
		utils.RespondWithError(w, http.StatusBadRequest, "Invalid event ID")
		return
	}

	if err := h.eventService.DeleteEvent(uint(eventID)); err != nil {
		h.logger.Error("failed to delete event",
			zap.Uint("event_id", uint(eventID)),
			zap.Error(err),
		)
		utils.RespondWithError(w, http.StatusInternalServerError, "Failed to delete event: "+err.Error())
		return
	}

	h.logger.Info("event deleted successfully",
		zap.Uint("event_id", uint(eventID)),
	)

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

// GetEventsByType возвращает события по типу
func (h *EventHandler) GetEventsByType(w http.ResponseWriter, r *http.Request) {
	h.logger.Info("handling get events by type request",
		zap.String("method", r.Method),
		zap.String("path", r.URL.Path),
		zap.String("remote_addr", r.RemoteAddr),
	)

	eventType := models.EventType(r.PathValue("type"))

	// Валидация типа события
	validTypes := []models.EventType{"race", "training", "social", "workshop"}
	if !isValidEventType(eventType, validTypes) {
		h.logger.Warn("invalid event type", zap.String("event_type", string(eventType)))
		utils.RespondWithError(w, http.StatusBadRequest, "Invalid event type")
		return
	}

	events, err := h.eventService.GetEventsByType(eventType)
	if err != nil {
		h.logger.Error("failed to get events by type",
			zap.String("event_type", string(eventType)),
			zap.Error(err),
		)
		utils.RespondWithError(w, http.StatusInternalServerError, "Failed to get events: "+err.Error())
		return
	}

	var eventResponses []EventResponse
	for _, event := range events {
		eventResponses = append(eventResponses, toEventResponse(&event))
	}

	h.logger.Info("events by type retrieved successfully",
		zap.String("event_type", string(eventType)),
		zap.Int("events_count", len(eventResponses)),
	)

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

// GetUpcomingEvents возвращает предстоящие события
func (h *EventHandler) GetUpcomingEvents(w http.ResponseWriter, r *http.Request) {
	h.logger.Info("handling get upcoming events request",
		zap.String("method", r.Method),
		zap.String("path", r.URL.Path),
		zap.String("remote_addr", r.RemoteAddr),
	)

	events, err := h.eventService.GetUpcomingEvents()
	if err != nil {
		h.logger.Error("failed to get upcoming events", zap.Error(err))
		utils.RespondWithError(w, http.StatusInternalServerError, "Failed to get upcoming events: "+err.Error())
		return
	}

	var eventResponses []EventResponse
	for _, event := range events {
		eventResponses = append(eventResponses, toEventResponse(&event))
	}

	h.logger.Info("upcoming events retrieved successfully",
		zap.Int("events_count", len(eventResponses)),
	)

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

// ToggleRegistrationStatus переключает статус регистрации
func (h *EventHandler) ToggleRegistrationStatus(w http.ResponseWriter, r *http.Request) {
	h.logger.Info("handling toggle registration status 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("toggle registration status failed - authentication required")
		utils.RespondWithError(w, http.StatusUnauthorized, "Authentication required")
		return
	}

	if user.Role != "admin" {
		h.logger.Warn("toggle registration status failed - insufficient permissions",
			zap.Uint("user_id", user.ID),
			zap.String("user_role", user.Role),
		)
		utils.RespondWithError(w, http.StatusForbidden, "Insufficient permissions")
		return
	}

	// Извлекаем ID события
	eventID, err := strconv.ParseUint(r.PathValue("id"), 10, 32)
	if err != nil {
		h.logger.Warn("invalid event ID", zap.Error(err))
		utils.RespondWithError(w, http.StatusBadRequest, "Invalid event ID")
		return
	}

	var req struct {
		RegistrationOpen bool `json:"registration_open" validate:"required"`
	}

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

	if err := h.eventService.ToggleRegistrationStatus(uint(eventID), req.RegistrationOpen); err != nil {
		h.logger.Error("failed to toggle registration status",
			zap.Uint("event_id", uint(eventID)),
			zap.Bool("registration_open", req.RegistrationOpen),
			zap.Error(err),
		)
		utils.RespondWithError(w, http.StatusInternalServerError, "Failed to toggle registration status: "+err.Error())
		return
	}

	h.logger.Info("registration status toggled successfully",
		zap.Uint("event_id", uint(eventID)),
		zap.Bool("registration_open", req.RegistrationOpen),
	)

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

// toEventResponse преобразует модель события в response DTO
func toEventResponse(event *models.Event) EventResponse {
	return EventResponse{
		ID:                event.ID,
		Title:             event.Title,
		Description:       event.Description,
		Date:              event.Date,
		Location:          event.Location,
		Type:              event.Type,
		Distance:          event.Distance,
		ParticipantsCount: event.ParticipantsCount,
		MaxParticipants:   event.MaxParticipants,
		RegistrationOpen:  event.RegistrationOpen,
		Image:             event.Image,
		CreatedAt:         event.CreatedAt,
		UpdatedAt:         event.UpdatedAt,
	}
}

// isValidEventType проверяет валидность типа события
func isValidEventType(eventType models.EventType, validTypes []models.EventType) bool {
	for _, validType := range validTypes {
		if eventType == validType {
			return true
		}
	}
	return false
}
