package handlers

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

	"git.kirlllll.ru/volontery/backend/internal/api/middleware"
	"git.kirlllll.ru/volontery/backend/internal/database"
	"git.kirlllll.ru/volontery/backend/internal/service"
	"github.com/go-chi/chi/v5"
)

// RequestHandler обрабатывает запросы заявок
type RequestHandler struct {
	requestService *service.RequestService
}

// NewRequestHandler создает новый RequestHandler
func NewRequestHandler(requestService *service.RequestService) *RequestHandler {
	return &RequestHandler{
		requestService: requestService,
	}
}

// CreateRequest создает новую заявку
// POST /api/v1/requests
func (h *RequestHandler) CreateRequest(w http.ResponseWriter, r *http.Request) {
	userID, ok := middleware.GetUserIDFromContext(r.Context())
	if !ok {
		respondError(w, http.StatusUnauthorized, "unauthorized")
		return
	}

	var input service.CreateRequestInput
	if err := json.NewDecoder(r.Body).Decode(&input); err != nil {
		respondError(w, http.StatusBadRequest, "invalid request body")
		return
	}

	input.RequesterID = userID

	request, err := h.requestService.CreateRequest(r.Context(), input)
	if err != nil {
		respondError(w, http.StatusBadRequest, err.Error())
		return
	}

	respondJSON(w, http.StatusCreated, request)
}

// GetRequest получает заявку по ID
// GET /api/v1/requests/{id}
func (h *RequestHandler) GetRequest(w http.ResponseWriter, r *http.Request) {
	idStr := chi.URLParam(r, "id")
	requestID, err := strconv.ParseInt(idStr, 10, 64)
	if err != nil {
		respondError(w, http.StatusBadRequest, "invalid request id")
		return
	}

	request, err := h.requestService.GetRequest(r.Context(), requestID)
	if err != nil {
		respondError(w, http.StatusNotFound, "request not found")
		return
	}

	respondJSON(w, http.StatusOK, request)
}

// GetMyRequests получает заявки текущего пользователя
// GET /api/v1/requests/my
func (h *RequestHandler) GetMyRequests(w http.ResponseWriter, r *http.Request) {
	userID, ok := middleware.GetUserIDFromContext(r.Context())
	if !ok {
		respondError(w, http.StatusUnauthorized, "unauthorized")
		return
	}

	limit, offset := parsePagination(r)

	requests, err := h.requestService.GetUserRequests(r.Context(), userID, limit, offset)
	if err != nil {
		respondError(w, http.StatusInternalServerError, "failed to get requests")
		return
	}

	respondJSON(w, http.StatusOK, requests)
}

// FindNearbyRequests ищет заявки рядом с точкой
// GET /api/v1/requests/nearby
func (h *RequestHandler) FindNearbyRequests(w http.ResponseWriter, r *http.Request) {
	latStr := r.URL.Query().Get("lat")
	lonStr := r.URL.Query().Get("lon")
	radiusStr := r.URL.Query().Get("radius")

	if latStr == "" || lonStr == "" {
		respondError(w, http.StatusBadRequest, "lat and lon are required")
		return
	}

	lat, err := strconv.ParseFloat(latStr, 64)
	if err != nil {
		respondError(w, http.StatusBadRequest, "invalid latitude")
		return
	}

	lon, err := strconv.ParseFloat(lonStr, 64)
	if err != nil {
		respondError(w, http.StatusBadRequest, "invalid longitude")
		return
	}

	radius := 5000.0 // default 5km
	if radiusStr != "" {
		radius, err = strconv.ParseFloat(radiusStr, 64)
		if err != nil {
			respondError(w, http.StatusBadRequest, "invalid radius")
			return
		}
	}

	limit, offset := parsePagination(r)

	// По умолчанию ищем только активные заявки
	statuses := []database.RequestStatus{
		database.RequestStatusPendingModeration,
		database.RequestStatusApproved,
		database.RequestStatusInProgress,
	}

	requests, err := h.requestService.FindNearbyRequests(r.Context(), lat, lon, radius, statuses, limit, offset)
	if err != nil {
		respondError(w, http.StatusInternalServerError, fmt.Sprintf("failed to find requests: %v", err))
		return
	}

	respondJSON(w, http.StatusOK, requests)
}

// FindRequestsInBounds ищет заявки в прямоугольной области
// GET /api/v1/requests/bounds
func (h *RequestHandler) FindRequestsInBounds(w http.ResponseWriter, r *http.Request) {
	minLonStr := r.URL.Query().Get("min_lon")
	minLatStr := r.URL.Query().Get("min_lat")
	maxLonStr := r.URL.Query().Get("max_lon")
	maxLatStr := r.URL.Query().Get("max_lat")

	if minLonStr == "" || minLatStr == "" || maxLonStr == "" || maxLatStr == "" {
		respondError(w, http.StatusBadRequest, "min_lon, min_lat, max_lon, max_lat are required")
		return
	}

	minLon, err := strconv.ParseFloat(minLonStr, 64)
	if err != nil {
		respondError(w, http.StatusBadRequest, "invalid min_lon")
		return
	}

	minLat, err := strconv.ParseFloat(minLatStr, 64)
	if err != nil {
		respondError(w, http.StatusBadRequest, "invalid min_lat")
		return
	}

	maxLon, err := strconv.ParseFloat(maxLonStr, 64)
	if err != nil {
		respondError(w, http.StatusBadRequest, "invalid max_lon")
		return
	}

	maxLat, err := strconv.ParseFloat(maxLatStr, 64)
	if err != nil {
		respondError(w, http.StatusBadRequest, "invalid max_lat")
		return
	}

	// По умолчанию ищем только активные заявки
	statuses := []database.RequestStatus{
		database.RequestStatusPendingModeration,
		database.RequestStatusApproved,
		database.RequestStatusInProgress,
	}

	requests, err := h.requestService.FindRequestsInBounds(r.Context(), statuses, minLon, minLat, maxLon, maxLat)
	if err != nil {
		respondError(w, http.StatusInternalServerError, fmt.Sprintf("failed to find requests: %v", err))
		return
	}

	respondJSON(w, http.StatusOK, requests)
}

// CreateVolunteerResponse создает отклик волонтера на заявку
// POST /api/v1/requests/{id}/responses
func (h *RequestHandler) CreateVolunteerResponse(w http.ResponseWriter, r *http.Request) {
	userID, ok := middleware.GetUserIDFromContext(r.Context())
	if !ok {
		respondError(w, http.StatusUnauthorized, "unauthorized")
		return
	}

	idStr := chi.URLParam(r, "id")
	requestID, err := strconv.ParseInt(idStr, 10, 64)
	if err != nil {
		respondError(w, http.StatusBadRequest, "invalid request id")
		return
	}

	var input struct {
		Message string `json:"message"`
	}

	if err := json.NewDecoder(r.Body).Decode(&input); err != nil {
		respondError(w, http.StatusBadRequest, "invalid request body")
		return
	}

	response, err := h.requestService.CreateVolunteerResponse(r.Context(), requestID, userID, input.Message)
	if err != nil {
		respondError(w, http.StatusBadRequest, err.Error())
		return
	}

	respondJSON(w, http.StatusCreated, response)
}

// GetRequestResponses получает отклики на заявку
// GET /api/v1/requests/{id}/responses
func (h *RequestHandler) GetRequestResponses(w http.ResponseWriter, r *http.Request) {
	idStr := chi.URLParam(r, "id")
	requestID, err := strconv.ParseInt(idStr, 10, 64)
	if err != nil {
		respondError(w, http.StatusBadRequest, "invalid request id")
		return
	}

	responses, err := h.requestService.GetRequestResponses(r.Context(), requestID)
	if err != nil {
		respondError(w, http.StatusInternalServerError, "failed to get responses")
		return
	}

	respondJSON(w, http.StatusOK, responses)
}

// ListRequestTypes получает список типов заявок
// GET /api/v1/request-types
func (h *RequestHandler) ListRequestTypes(w http.ResponseWriter, r *http.Request) {
	types, err := h.requestService.ListRequestTypes(r.Context())
	if err != nil {
		respondError(w, http.StatusInternalServerError, "failed to get request types")
		return
	}

	respondJSON(w, http.StatusOK, types)
}

// GetPendingModerationRequests получает заявки на модерации
// GET /api/v1/moderation/requests/pending
func (h *RequestHandler) GetPendingModerationRequests(w http.ResponseWriter, r *http.Request) {
	limit, offset := parsePagination(r)

	requests, err := h.requestService.GetPendingModerationRequests(r.Context(), limit, offset)
	if err != nil {
		respondError(w, http.StatusInternalServerError, "failed to get pending requests")
		return
	}

	respondJSON(w, http.StatusOK, requests)
}

// ApproveRequest одобряет заявку
// POST /api/v1/moderation/requests/{id}/approve
func (h *RequestHandler) ApproveRequest(w http.ResponseWriter, r *http.Request) {
	moderatorID, ok := middleware.GetUserIDFromContext(r.Context())
	if !ok {
		respondError(w, http.StatusUnauthorized, "unauthorized")
		return
	}

	idStr := chi.URLParam(r, "id")
	requestID, err := strconv.ParseInt(idStr, 10, 64)
	if err != nil {
		respondError(w, http.StatusBadRequest, "invalid request id")
		return
	}

	var input struct {
		Comment *string `json:"comment"`
	}

	if err := json.NewDecoder(r.Body).Decode(&input); err != nil {
		respondError(w, http.StatusBadRequest, "invalid request body")
		return
	}

	if err := h.requestService.ApproveRequest(r.Context(), requestID, moderatorID, input.Comment); err != nil {
		respondError(w, http.StatusBadRequest, err.Error())
		return
	}

	respondJSON(w, http.StatusOK, map[string]string{"status": "approved"})
}

// RejectRequest отклоняет заявку
// POST /api/v1/moderation/requests/{id}/reject
func (h *RequestHandler) RejectRequest(w http.ResponseWriter, r *http.Request) {
	moderatorID, ok := middleware.GetUserIDFromContext(r.Context())
	if !ok {
		respondError(w, http.StatusUnauthorized, "unauthorized")
		return
	}

	idStr := chi.URLParam(r, "id")
	requestID, err := strconv.ParseInt(idStr, 10, 64)
	if err != nil {
		respondError(w, http.StatusBadRequest, "invalid request id")
		return
	}

	var input struct {
		Comment string `json:"comment"`
	}

	if err := json.NewDecoder(r.Body).Decode(&input); err != nil {
		respondError(w, http.StatusBadRequest, "invalid request body")
		return
	}

	if err := h.requestService.RejectRequest(r.Context(), requestID, moderatorID, input.Comment); err != nil {
		respondError(w, http.StatusBadRequest, err.Error())
		return
	}

	respondJSON(w, http.StatusOK, map[string]string{"status": "rejected"})
}

// GetMyModeratedRequests получает заявки, модерированные текущим модератором
// GET /api/v1/moderation/requests/my
func (h *RequestHandler) GetMyModeratedRequests(w http.ResponseWriter, r *http.Request) {
	moderatorID, ok := middleware.GetUserIDFromContext(r.Context())
	if !ok {
		respondError(w, http.StatusUnauthorized, "unauthorized")
		return
	}

	limit, offset := parsePagination(r)

	requests, err := h.requestService.GetModeratedRequests(r.Context(), moderatorID, limit, offset)
	if err != nil {
		respondError(w, http.StatusInternalServerError, "failed to get moderated requests")
		return
	}

	respondJSON(w, http.StatusOK, requests)
}

// AcceptVolunteerResponseHandler принимает отклик волонтера
// POST /api/v1/requests/{id}/responses/{response_id}/accept
func (h *RequestHandler) AcceptVolunteerResponseHandler(w http.ResponseWriter, r *http.Request) {
	requesterID, ok := middleware.GetUserIDFromContext(r.Context())
	if !ok {
		respondError(w, http.StatusUnauthorized, "unauthorized")
		return
	}

	responseIDStr := chi.URLParam(r, "response_id")
	responseID, err := strconv.ParseInt(responseIDStr, 10, 64)
	if err != nil {
		respondError(w, http.StatusBadRequest, "invalid response id")
		return
	}

	result, err := h.requestService.AcceptVolunteerResponse(r.Context(), responseID, requesterID)
	if err != nil {
		respondError(w, http.StatusBadRequest, err.Error())
		return
	}

	if !result.Success {
		respondError(w, http.StatusBadRequest, result.Message)
		return
	}

	respondJSON(w, http.StatusOK, map[string]interface{}{
		"success":      result.Success,
		"message":      result.Message,
		"request_id":   result.RequestID,
		"volunteer_id": result.VolunteerID,
	})
}

// CompleteRequestWithRatingHandler завершает заявку с рейтингом
// POST /api/v1/requests/{id}/complete
func (h *RequestHandler) CompleteRequestWithRatingHandler(w http.ResponseWriter, r *http.Request) {
	requesterID, ok := middleware.GetUserIDFromContext(r.Context())
	if !ok {
		respondError(w, http.StatusUnauthorized, "unauthorized")
		return
	}

	idStr := chi.URLParam(r, "id")
	requestID, err := strconv.ParseInt(idStr, 10, 64)
	if err != nil {
		respondError(w, http.StatusBadRequest, "invalid request id")
		return
	}

	var input struct {
		Rating  int32   `json:"rating"`
		Comment *string `json:"comment"`
	}

	if err := json.NewDecoder(r.Body).Decode(&input); err != nil {
		respondError(w, http.StatusBadRequest, "invalid request body")
		return
	}

	result, err := h.requestService.CompleteRequestWithRating(r.Context(), requestID, requesterID, input.Rating, input.Comment)
	if err != nil {
		respondError(w, http.StatusBadRequest, err.Error())
		return
	}

	if !result.Success {
		respondError(w, http.StatusBadRequest, result.Message)
		return
	}

	respondJSON(w, http.StatusOK, map[string]interface{}{
		"success":   result.Success,
		"message":   result.Message,
		"rating_id": result.RatingID,
	})
}

// parsePagination парсит параметры пагинации из запроса
func parsePagination(r *http.Request) (limit, offset int32) {
	limitStr := r.URL.Query().Get("limit")
	offsetStr := r.URL.Query().Get("offset")

	limit = 20 // default
	if limitStr != "" {
		if l, err := strconv.ParseInt(limitStr, 10, 32); err == nil && l > 0 && l <= 100 {
			limit = int32(l)
		}
	}

	offset = 0
	if offsetStr != "" {
		if o, err := strconv.ParseInt(offsetStr, 10, 32); err == nil && o >= 0 {
			offset = int32(o)
		}
	}

	return limit, offset
}
