package feedback

import (
	"errors"
	"tm/internal/customer"
	"tm/internal/user"
	"tm/pkg/logger"
	"tm/pkg/response"

	"github.com/asaskevich/govalidator"
	"github.com/labstack/echo/v4"
)

// Handler handles HTTP requests for feedback operations
type Handler struct {
	service         Service
	logger          logger.Logger
	userHandler     *user.Handler
	customerHandler *customer.Handler
}

// NewHandler creates a new feedback handler
func NewHandler(
	service Service,
	userHandler *user.Handler,
	customerHandler *customer.Handler,
	logger logger.Logger,
) *Handler {
	return &Handler{
		service:         service,
		logger:          logger,
		userHandler:     userHandler,
		customerHandler: customerHandler,
	}
}

// *************** ADMIN ***************
// ListFeedback retrieves feedback with pagination and filtering
// @Summary List feedback with filters
// @Description Retrieve paginated list of feedback with optional filtering by various criteria. This endpoint is for administrative use and provides comprehensive filtering options.
// @Tags Admin-Feedback
// @Accept json
// @Produce json
// @Param tender_id query string false "Filter by tender ID (MongoDB ObjectID format)"
// @Param customer_id query string false "Filter by customer ID (MongoDB ObjectID format)"
// @Param company_id query string false "Filter by company ID (MongoDB ObjectID format)"
// @Param feedback_type query string false "Filter by feedback type" Enums(like, dislike)
// @Param date_from query int64 false "Filter by creation date from (Unix timestamp in seconds)"
// @Param date_to query int64 false "Filter by creation date to (Unix timestamp in seconds)"
// @Param limit query int false "Number of items per page (default: 20, max: 100)" minimum(1) maximum(100)
// @Param offset query int false "Number of items to skip for pagination (default: 0)" minimum(0)
// @Success 200 {object} response.APIResponse{data=FeedbackListResponse} "Feedback list retrieved successfully"
// @Failure 400 {object} response.APIResponse{error=string,message=string} "Bad request - Invalid query parameters"
// @Failure 422 {object} response.APIResponse{error=string,message=string} "Validation error - Invalid filter criteria"
// @Failure 500 {object} response.APIResponse{error=string,message=string} "Internal server error"
// @Security BearerAuth
// @Router /admin/v1/feedback [get]
func (h *Handler) Search(c echo.Context) error {
	form, err := response.Parse[SearchForm](c)
	if err != nil {
		return response.ValidationError(c, "Invalid request data", err.Error())
	}

	pagination, err := response.NewPagination(c)
	if err != nil {
		return response.PaginationBadRequest(c, err)
	}

	feedbackList, err := h.service.Search(c.Request().Context(), *form, pagination)
	if err != nil {
		if response.IsListPaginationError(err) {
			return response.PaginationBadRequest(c, err)
		}
		return response.InternalServerError(c, "Failed to retrieve feedback list")
	}

	return response.SuccessWithMeta(c, feedbackList, feedbackList.Meta, "feedback list retrieved successfully")
}

// GetFeedbackByID retrieves feedback by ID with loaded related data
// @Summary Get feedback by ID
// @Description Retrieve feedback details by its unique identifier with loaded tender, customer, and company information. This endpoint provides comprehensive feedback data including related entity details.
// @Tags Admin-Feedback
// @Accept json
// @Produce json
// @Param id path string true "Feedback ID (MongoDB ObjectID format)" minlength(24) maxlength(24)
// @Success 200 {object} response.APIResponse{data=FeedbackResponse} "feedback retrieved successfully"
// @Failure 400 {object} response.APIResponse{error=string,message=string} "Bad request - Invalid feedback ID format"
// @Failure 404 {object} response.APIResponse{error=string,message=string} "Feedback not found"
// @Failure 500 {object} response.APIResponse{error=string,message=string} "Internal server error"
// @Security BearerAuth
// @Router /admin/v1/feedback/{id} [get]
func (h *Handler) Get(c echo.Context) error {
	feedbackID := c.Param("id")
	if feedbackID == "" {
		return response.BadRequest(c, "Feedback ID is required", "Feedback ID parameter is missing")
	}

	feedback, err := h.service.Get(c.Request().Context(), feedbackID)
	if err != nil {
		if errors.Is(err, ErrFeedbackNotFound) {
			return response.NotFound(c, "Feedback not found")
		}
		if errors.Is(err, ErrFeedbackDeleted) {
			return response.NotFound(c, "Feedback has been deleted")
		}
		return response.InternalServerError(c, "Failed to retrieve feedback")
	}

	return response.Success(c, feedback, "feedback retrieved successfully")
}

// SoftDeleteFeedback marks feedback as deleted without removing it
// @Summary Soft delete feedback
// @Description Mark feedback as deleted without permanently removing it from the database. The feedback will be marked as deleted and hidden from normal queries but can be restored if needed.
// @Tags Admin-Feedback
// @Accept json
// @Produce json
// @Param id path string true "Feedback ID (MongoDB ObjectID format)" minlength(24) maxlength(24)
// @Success 200 {object} response.APIResponse{message=string} "Feedback soft deleted successfully"
// @Failure 400 {object} response.APIResponse{error=string,message=string} "Bad request - Invalid feedback ID format"
// @Failure 401 {object} response.APIResponse{error=string,message=string} "Unauthorized - User not authenticated"
// @Failure 403 {object} response.APIResponse{error=string,message=string} "Forbidden - User not authorized to delete this feedback"
// @Failure 404 {object} response.APIResponse{error=string,message=string} "Not found - Feedback not found"
// @Failure 500 {object} response.APIResponse{error=string,message=string} "Internal server error"
// @Security BearerAuth
// @Router /admin/v1/feedback/{id} [delete]
func (h *Handler) Delete(c echo.Context) error {
	id := c.Param("id")
	if id == "" {
		return response.BadRequest(c, "Feedback ID is required", "")
	}

	// Call service
	err := h.service.Delete(c.Request().Context(), id)
	if err != nil {
		switch err {
		case ErrFeedbackNotFound:
			return response.BadRequest(c, "Feedback not found", "")
		case ErrUnauthorizedAccess:
			return response.Forbidden(c, "You are not authorized to delete this feedback")
		default:
			return response.InternalServerError(c, "Failed to soft delete feedback")
		}
	}

	return response.Success(c, nil, "Feedback soft deleted successfully")
}

// *************** PUBLIC ***************
// ToggleFeedback toggles between like and dislike for a tender
// @Summary Toggle feedback for a tender
// @Description Toggle between like and dislike for a tender, or create a like if no feedback exists. This endpoint allows users to express their preference for tenders and automatically handles the toggle logic.
// @Tags Feedback
// @Accept json
// @Produce json
// @Param feedback body ToggleFeedbackForm true "Feedback toggle request containing tender ID"
// @Success 200 {object} response.APIResponse{data=FeedbackResponse} "Feedback toggled successfully"
// @Failure 400 {object} response.APIResponse{error=string,message=string} "Bad request - Invalid input data or missing customer/company association"
// @Failure 401 {object} response.APIResponse{error=string,message=string} "Unauthorized - User not authenticated"
// @Failure 422 {object} response.APIResponse{error=string,message=string} "Validation error - Invalid request data format"
// @Failure 500 {object} response.APIResponse{error=string,message=string} "Internal server error"
// @Security BearerAuth
// @Router /api/v1/feedback [post]
func (h *Handler) Toggle(c echo.Context) error {
	form, err := response.Parse[ToggleFeedbackForm](c)
	if err != nil {
		return response.ValidationError(c, "Invalid request data", err.Error())
	}

	// Validate form using govalidator
	if _, err := govalidator.ValidateStruct(form); err != nil {
		return response.ValidationError(c, "Validation failed", err.Error())
	}

	// Get customer ID from context
	customerID, err := customer.GetCustomerIDFromContext(c)
	if err != nil {
		return response.BadRequest(c, "Customer ID required", "User must be associated with a customer")
	}

	// Get company ID from context
	companyID, err := user.GetCompanyIDFromContext(c)
	if err != nil {
		return response.BadRequest(c, "Company ID required", "User must be associated with a company")
	}

	// Call service
	result, err := h.service.Toggle(c.Request().Context(), *form, &customerID, &companyID)
	if err != nil {
		return response.InternalServerError(c, "Failed to toggle feedback")
	}

	return response.Success(c, result, "Feedback toggled successfully")
}

// ListFeedback retrieves feedback with pagination and filtering
// @Summary List feedback with filters
// @Description Retrieve paginated list of feedback for the authenticated customer with optional filters.
// @Tags Feedback
// @Accept json
// @Produce json
// @Param tender_id query string false "Filter by tender ID (MongoDB ObjectID format)"
// @Param customer_id query string false "Filter by customer ID (MongoDB ObjectID format)"
// @Param company_id query string false "Filter by company ID (MongoDB ObjectID format)"
// @Param feedback_type query string false "Filter by feedback type" Enums(like, dislike)
// @Param date_from query int64 false "Filter by creation date from (Unix timestamp in seconds)" minimum(0)
// @Param date_to query int64 false "Filter by creation date to (Unix timestamp in seconds)" minimum(0)
// @Param limit query int false "Number of items per page (default: 20, max: 100)" minimum(1) maximum(100)
// @Param offset query int false "Number of items to skip for pagination (default: 0)" minimum(0)
// @Success 200 {object} response.APIResponse{data=FeedbackListResponse} "Feedback list retrieved successfully"
// @Failure 400 {object} response.APIResponse{error=string,message=string} "Bad request - Invalid query parameters or missing company association"
// @Failure 422 {object} response.APIResponse{error=string,message=string} "Validation error - Invalid filter criteria"
// @Failure 500 {object} response.APIResponse{error=string,message=string} "Internal server error"
// @Security BearerAuth
// @Router /api/v1/feedback [get]
func (h *Handler) PublicList(c echo.Context) error {
	customerID, err := customer.GetCustomerIDFromContext(c)
	if err != nil {
		return response.BadRequest(c, "Customer ID required", "User must be associated with a customer")
	}

	form, err := response.Parse[SearchForm](c)
	if err != nil {
		return response.ValidationError(c, "Invalid request data", err.Error())
	}
	form.Customer = &customerID

	pagination, err := response.NewPagination(c)
	if err != nil {
		return response.PaginationBadRequest(c, err)
	}

	result, err := h.service.Search(c.Request().Context(), *form, pagination)
	if err != nil {
		if response.IsListPaginationError(err) {
			return response.PaginationBadRequest(c, err)
		}
		return response.InternalServerError(c, "Failed to list feedback")
	}

	return response.SuccessWithMeta(c, result, result.Meta, "Feedback list retrieved successfully")
}

// PublicGetFeedback retrieves feedback by ID
// @Summary Get feedback by ID
// @Description Retrieve feedback details by its unique identifier. This endpoint provides basic feedback information for public users.
// @Tags Feedback
// @Accept json
// @Produce json
// @Param id path string true "Feedback ID (MongoDB ObjectID format)" minlength(24) maxlength(24)
// @Success 200 {object} response.APIResponse{data=FeedbackResponse} "Feedback retrieved successfully"
// @Failure 400 {object} response.APIResponse{error=string,message=string} "Bad request - Invalid feedback ID format"
// @Failure 404 {object} response.APIResponse{error=string,message=string} "Feedback not found"
// @Failure 500 {object} response.APIResponse{error=string,message=string} "Internal server error"
// @Security BearerAuth
// @Router /api/v1/feedback/{id} [get]
func (h *Handler) PublicGet(c echo.Context) error {
	feedbackID := c.Param("id")
	if feedbackID == "" {
		return response.BadRequest(c, "Feedback ID is required", "Feedback ID parameter is missing")
	}

	feedback, err := h.service.Get(c.Request().Context(), feedbackID)
	if err != nil {
		if errors.Is(err, ErrFeedbackNotFound) {
			return response.NotFound(c, "Feedback not found")
		}
		return response.InternalServerError(c, "Failed to get feedback")
	}

	return response.Success(c, feedback, "Feedback retrieved successfully")
}

// PublicGetFeedbackByTenderID retrieves feedback by tender ID
// @Summary Get feedback by tender ID
// @Description Retrieve feedback details by tender ID. This endpoint provides basic feedback information for public users.
// @Tags Feedback
// @Accept json
// @Produce json
// @Param tender_id path string true "Tender ID (MongoDB ObjectID format)" minlength(24) maxlength(24)
// @Success 200 {object} response.APIResponse{data=FeedbackResponse} "Feedback retrieved successfully"
// @Failure 400 {object} response.APIResponse{error=string,message=string} "Bad request - Invalid tender ID format"
// @Failure 404 {object} response.APIResponse{error=string,message=string} "Feedback not found"
// @Failure 500 {object} response.APIResponse{error=string,message=string} "Internal server error"
// @Security BearerAuth
// @Router /api/v1/feedback/tender/{tender_id} [get]
func (h *Handler) PublicGetByTenderID(c echo.Context) error {
	tenderID := c.Param("tender_id")
	if tenderID == "" {
		return response.BadRequest(c, "Tender ID is required", "Tender ID parameter is missing")
	}

	customerID, err := customer.GetCustomerIDFromContext(c)
	if err != nil {
		return response.BadRequest(c, "Customer ID required", "User must be associated with a customer")
	}

	feedback, err := h.service.GetByTenderIDForCustomer(c.Request().Context(), tenderID, customerID)
	if err != nil {
		if errors.Is(err, ErrFeedbackNotFound) {
			return response.NotFound(c, "Feedback not found")
		}
		return response.InternalServerError(c, "Failed to get feedback")
	}

	return response.Success(c, feedback, "Feedback retrieved successfully")
}

// GetCustomerStats retrieves feedback statistics for the authenticated customer.
// @Summary Get customer feedback statistics
// @Description Retrieve feedback statistics (likes, dislikes, totals) for the authenticated customer only.
// @Tags Feedback
// @Accept json
// @Produce json
// @Success 200 {object} response.APIResponse{data=CustomerStatsResponse} "Customer feedback statistics retrieved successfully"
// @Failure 400 {object} response.APIResponse{error=string,message=string} "Bad request - Missing customer association"
// @Failure 401 {object} response.APIResponse{error=string,message=string} "Unauthorized - User not authenticated"
// @Failure 500 {object} response.APIResponse{error=string,message=string} "Internal server error"
// @Security BearerAuth
// @Router /api/v1/feedback/stats/customer [get]
func (h *Handler) GetCustomerStats(c echo.Context) error {
	customerID, err := customer.GetCustomerIDFromContext(c)
	if err != nil {
		return response.BadRequest(c, "Customer ID required", "User must be associated with a customer")
	}

	stats, err := h.service.CustomerStats(c.Request().Context(), customerID)
	if err != nil {
		return response.InternalServerError(c, "Failed to retrieve customer stats")
	}

	return response.Success(c, stats, "Customer stats retrieved successfully")
}

// GetCompanyStats returns customer-scoped stats for backward compatibility with clients using /stats/company.
// @Summary Get feedback statistics (customer-scoped, legacy path)
// @Description Same as GET /feedback/stats/customer. Prefer /stats/customer for new integrations.
// @Tags Feedback
// @Accept json
// @Produce json
// @Success 200 {object} response.APIResponse{data=CustomerStatsResponse} "Customer feedback statistics retrieved successfully"
// @Failure 400 {object} response.APIResponse{error=string,message=string} "Bad request - Missing customer association"
// @Failure 401 {object} response.APIResponse{error=string,message=string} "Unauthorized - User not authenticated"
// @Failure 500 {object} response.APIResponse{error=string,message=string} "Internal server error"
// @Security BearerAuth
// @Router /api/v1/feedback/stats/company [get]
func (h *Handler) GetCompanyStats(c echo.Context) error {
	return h.GetCustomerStats(c)
}
