package handlers

import (
	"Yimaru-Backend/internal/domain"
	"Yimaru-Backend/internal/web_server/ws"
	"bufio"
	"context"
	"encoding/json"
	"fmt"
	"net"
	"net/http"
	"strconv"
	"time"

	"github.com/gofiber/fiber/v2"
	"github.com/gorilla/websocket"
	"go.uber.org/zap"
)

func (h *Handler) ConnectSocket(c *fiber.Ctx) error {
	userID, ok := c.Locals("userID").(int64)
	if !ok || userID == 0 {
		h.mongoLoggerSvc.Info("Invalid user ID in context",
			zap.Int64("userID", userID),
			zap.Int("status_code", fiber.StatusUnauthorized),
			zap.Time("timestamp", time.Now()),
		)
		return fiber.NewError(fiber.StatusUnauthorized, "Invalid user identification")
	}

	// Convert fasthttp request to net/http request for gorilla upgrader
	stdReq := &http.Request{
		Method: http.MethodGet,
		Header: make(http.Header),
	}
	c.Context().Request.Header.VisitAll(func(key, value []byte) {
		stdReq.Header.Set(string(key), string(value))
	})
	stdReq.Host = string(c.Context().Host())
	stdReq.RequestURI = string(c.Context().RequestURI())

	// Hijack the underlying net.Conn from fasthttp
	// The hijack callback runs after the handler returns, so we must not block.
	c.Context().HijackSetNoResponse(true)
	c.Context().Hijack(func(netConn net.Conn) {
		// Create a hijackable response writer around the raw connection
		hjRW := &hijackResponseWriter{
			conn: netConn,
			brw:  bufio.NewReadWriter(bufio.NewReader(netConn), bufio.NewWriter(netConn)),
			h:    make(http.Header),
		}

		wsConn, err := ws.Upgrader.Upgrade(hjRW, stdReq, nil)
		if err != nil {
			h.mongoLoggerSvc.Error("WebSocket upgrade failed",
				zap.Int64("userID", userID),
				zap.Error(err),
				zap.Time("timestamp", time.Now()),
			)
			netConn.Close()
			return
		}

		client := &ws.Client{
			Conn:        wsConn,
			RecipientID: userID,
		}

		h.notificationSvc.Hub.Register <- client
		defer func() {
			h.notificationSvc.Hub.Unregister <- client
			wsConn.Close()
		}()

		h.mongoLoggerSvc.Info("WebSocket connection established",
			zap.Int64("userID", userID),
			zap.Time("timestamp", time.Now()),
		)

		for {
			_, _, err := wsConn.ReadMessage()
			if err != nil {
				if websocket.IsCloseError(err, websocket.CloseNormalClosure, websocket.CloseGoingAway) {
					h.mongoLoggerSvc.Info("WebSocket closed normally",
						zap.Int64("userID", userID),
						zap.Time("timestamp", time.Now()),
					)
				} else {
					h.mongoLoggerSvc.Info("Unexpected WebSocket closure",
						zap.Int64("userID", userID),
						zap.Error(err),
						zap.Time("timestamp", time.Now()),
					)
				}
				break
			}
		}
	})

	return nil
}

// hijackResponseWriter implements http.ResponseWriter and http.Hijacker
// so gorilla/websocket can upgrade over a raw net.Conn.
type hijackResponseWriter struct {
	conn net.Conn
	brw  *bufio.ReadWriter
	h    http.Header
}

func (w *hijackResponseWriter) Header() http.Header        { return w.h }
func (w *hijackResponseWriter) WriteHeader(statusCode int)  {}
func (w *hijackResponseWriter) Write(b []byte) (int, error) { return w.conn.Write(b) }
func (w *hijackResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
	return w.conn, w.brw, nil
}

func (h *Handler) MarkNotificationAsRead(c *fiber.Ctx) error {
	idStr := c.Params("id")
	id, err := strconv.ParseInt(idStr, 10, 64)
	if err != nil {
		return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
			Message: "Invalid notification ID",
			Error:   err.Error(),
		})
	}

	notification, err := h.notificationSvc.MarkNotificationAsRead(context.Background(), id)
	if err != nil {
		h.mongoLoggerSvc.Error("[NotificationHandler.MarkNotificationAsRead] Failed to mark notification as read",
			zap.Int64("notificationID", id),
			zap.Int("status_code", fiber.StatusInternalServerError),
			zap.Error(err),
			zap.Time("timestamp", time.Now()),
		)
		return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{
			Message: "Failed to mark notification as read",
			Error:   err.Error(),
		})
	}

	return c.Status(fiber.StatusOK).JSON(domain.Response{
		Message:    "Notification marked as read",
		Success:    true,
		StatusCode: fiber.StatusOK,
		Data:       notification,
	})
}

func (h *Handler) MarkAllNotificationsAsRead(c *fiber.Ctx) error {
	userID, ok := c.Locals("user_id").(int64)
	if !ok || userID == 0 {
		return c.Status(fiber.StatusUnauthorized).JSON(domain.ErrorResponse{
			Message: "Invalid user identification",
			Error:   "User ID not found in context",
		})
	}

	if err := h.notificationSvc.MarkAllUserNotificationsAsRead(context.Background(), userID); err != nil {
		h.mongoLoggerSvc.Error("[NotificationHandler.MarkAllNotificationsAsRead] Failed to mark all notifications as read",
			zap.Int64("userID", userID),
			zap.Int("status_code", fiber.StatusInternalServerError),
			zap.Error(err),
			zap.Time("timestamp", time.Now()),
		)
		return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{
			Message: "Failed to mark all notifications as read",
			Error:   err.Error(),
		})
	}

	return c.Status(fiber.StatusOK).JSON(domain.Response{
		Message:    "All notifications marked as read",
		Success:    true,
		StatusCode: fiber.StatusOK,
	})
}

func (h *Handler) MarkNotificationAsUnread(c *fiber.Ctx) error {
	idStr := c.Params("id")
	id, err := strconv.ParseInt(idStr, 10, 64)
	if err != nil {
		return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
			Message: "Invalid notification ID",
			Error:   err.Error(),
		})
	}

	notification, err := h.notificationSvc.MarkNotificationAsUnread(context.Background(), id)
	if err != nil {
		h.mongoLoggerSvc.Error("[NotificationHandler.MarkNotificationAsUnread] Failed to mark notification as unread",
			zap.Int64("notificationID", id),
			zap.Int("status_code", fiber.StatusInternalServerError),
			zap.Error(err),
			zap.Time("timestamp", time.Now()),
		)
		return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{
			Message: "Failed to mark notification as unread",
			Error:   err.Error(),
		})
	}

	return c.Status(fiber.StatusOK).JSON(domain.Response{
		Message:    "Notification marked as unread",
		Success:    true,
		StatusCode: fiber.StatusOK,
		Data:       notification,
	})
}

func (h *Handler) MarkAllNotificationsAsUnread(c *fiber.Ctx) error {
	userID, ok := c.Locals("user_id").(int64)
	if !ok || userID == 0 {
		return c.Status(fiber.StatusUnauthorized).JSON(domain.ErrorResponse{
			Message: "Invalid user identification",
			Error:   "User ID not found in context",
		})
	}

	if err := h.notificationSvc.MarkAllUserNotificationsAsUnread(context.Background(), userID); err != nil {
		h.mongoLoggerSvc.Error("[NotificationHandler.MarkAllNotificationsAsUnread] Failed to mark all notifications as unread",
			zap.Int64("userID", userID),
			zap.Int("status_code", fiber.StatusInternalServerError),
			zap.Error(err),
			zap.Time("timestamp", time.Now()),
		)
		return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{
			Message: "Failed to mark all notifications as unread",
			Error:   err.Error(),
		})
	}

	return c.Status(fiber.StatusOK).JSON(domain.Response{
		Message:    "All notifications marked as unread",
		Success:    true,
		StatusCode: fiber.StatusOK,
	})
}

func (h *Handler) DeleteUserNotifications(c *fiber.Ctx) error {
	userID, ok := c.Locals("user_id").(int64)
	if !ok || userID == 0 {
		return c.Status(fiber.StatusUnauthorized).JSON(domain.ErrorResponse{
			Message: "Invalid user identification",
			Error:   "User ID not found in context",
		})
	}

	if err := h.notificationSvc.DeleteUserNotifications(context.Background(), userID); err != nil {
		h.mongoLoggerSvc.Error("[NotificationHandler.DeleteUserNotifications] Failed to delete notifications",
			zap.Int64("userID", userID),
			zap.Int("status_code", fiber.StatusInternalServerError),
			zap.Error(err),
			zap.Time("timestamp", time.Now()),
		)
		return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{
			Message: "Failed to delete notifications",
			Error:   err.Error(),
		})
	}

	return c.Status(fiber.StatusOK).JSON(domain.Response{
		Message:    "Notifications deleted successfully",
		Success:    true,
		StatusCode: fiber.StatusOK,
	})
}

func (h *Handler) CreateAndSendNotification(c *fiber.Ctx) error {
	type Request struct {
		RecipientID     int64                             `json:"recipient_id" validate:"required_if=DeliveryScheme single"`
		Type            domain.NotificationType           `json:"type" validate:"required"`
		Level           domain.NotificationLevel          `json:"level" validate:"required"`
		ErrorSeverity   *domain.NotificationErrorSeverity `json:"error_severity"`
		Reciever        domain.NotificationRecieverSide   `json:"reciever" validate:"required"`
		DeliveryScheme  domain.NotificationDeliveryScheme `json:"delivery_scheme" validate:"required"`
		DeliveryChannel domain.DeliveryChannel            `json:"delivery_channel" validate:"required"`
		Payload         domain.NotificationPayload        `json:"payload" validate:"required"`
		Priority        int                               `json:"priority"`
		Metadata        json.RawMessage                   `json:"metadata,omitempty"`
	}

	var req Request
	if err := c.BodyParser(&req); err != nil {
		h.mongoLoggerSvc.Info("[NotificationSvc.CreateAndSendNotification] Failed to parse request body",
			zap.Int("status_code", fiber.StatusBadRequest),
			zap.Error(err),
			zap.Time("timestamp", time.Now()),
		)
		return fiber.NewError(fiber.StatusBadRequest, "Invalid request body")
	}

	// userID, ok := c.Locals("userID").(int64)
	// if !ok || userID == 0 {
	// 	h.logger.Error("[NotificationSvc.CreateAndSendNotification] Invalid user ID in context")
	// 	return fiber.NewError(fiber.StatusUnauthorized, "Invalid user identification")
	// }

	switch req.DeliveryScheme {
	case domain.NotificationDeliverySchemeSingle:
		// if req.Reciever == domain.NotificationRecieverSideCustomer {
		// 	h.logger.Warn("[NotificationSvc.CreateAndSendNotification] Unauthorized attempt to send notification", "recipientID", req.RecipientID)
		// 	return fiber.NewError(fiber.StatusForbidden, "Unauthorized to send notification to this recipient")
		// }

		errorSeverity := domain.NotificationErrorSeverityMedium
		if req.ErrorSeverity != nil {
			errorSeverity = *req.ErrorSeverity
		}

		notification := &domain.Notification{
			ID:              "",
			RecipientID:     req.RecipientID,
			ReceiverType:    domain.ReceiverTypeFromReciever(req.Reciever),
			Type:            req.Type,
			Level:           req.Level,
			ErrorSeverity:   errorSeverity,
			Reciever:        req.Reciever,
			IsRead:          false,
			DeliveryStatus:  domain.DeliveryStatusPending,
			DeliveryChannel: req.DeliveryChannel,
			Payload:         req.Payload,
			Priority:        req.Priority,
			Metadata:        req.Metadata,
		}

		if err := h.notificationSvc.SendNotification(context.Background(), notification); err != nil {
			h.mongoLoggerSvc.Error("[NotificationSvc.CreateAndSendNotification] Failed to send single notification",
				zap.Int64("recipientID", req.RecipientID),
				zap.Int("status_code", fiber.StatusInternalServerError),
				zap.Error(err),
				zap.Time("timestamp", time.Now()),
			)
			return fiber.NewError(fiber.StatusInternalServerError, "Failed to send notification:"+err.Error())
		}

		h.mongoLoggerSvc.Info("[NotificationSvc.CreateAndSendNotification] Single notification sent successfully",
			zap.Int64("recipientID", req.RecipientID),
			zap.String("type", string(req.Type)),
			zap.Time("timestamp", time.Now()),
		)
		return c.Status(fiber.StatusCreated).JSON(fiber.Map{"message": "Single notification sent successfully", "notification_id": notification.ID})

	case domain.NotificationDeliverySchemeBulk:
		recipients, _, err := h.userSvc.GetAllUsers(context.Background(), domain.UserFilter{
			Role: string(req.Reciever),
		})
		if err != nil {
			h.mongoLoggerSvc.Error("[NotificationSvc.CreateAndSendNotification] Failed to fetch recipients for bulk notification",
				zap.Int64("RecipientID", req.RecipientID),
				zap.String("Reciever", string(req.Reciever)),
				zap.Int("status_code", fiber.StatusInternalServerError),
				zap.Error(err),
				zap.Time("timestamp", time.Now()),
			)
			return fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch recipients:"+err.Error())
		}

		notificationIDs := make([]string, 0, len(recipients))
		for _, user := range recipients {
			errorSeverity := domain.NotificationErrorSeverityMedium
			if req.ErrorSeverity != nil {
				errorSeverity = *req.ErrorSeverity
			}

			notification := &domain.Notification{
				ID:              "",
				RecipientID:     user.ID,
				ReceiverType:    domain.ReceiverTypeFromReciever(req.Reciever),
				Type:            req.Type,
				Level:           req.Level,
				ErrorSeverity:   errorSeverity,
				Reciever:        req.Reciever,
				IsRead:          false,
				DeliveryStatus:  domain.DeliveryStatusPending,
				DeliveryChannel: req.DeliveryChannel,
				Payload:         req.Payload,
				Priority:        req.Priority,
				Metadata:        req.Metadata,
			}

			if err := h.notificationSvc.SendNotification(context.Background(), notification); err != nil {
				h.mongoLoggerSvc.Error("[NotificationSvc.CreateAndSendNotification] Failed to send bulk notification",
					zap.Int64("UserID", user.ID),
					zap.Error(err),
					zap.Time("timestamp", time.Now()),
				)
				continue
			}
			notificationIDs = append(notificationIDs, notification.ID)
		}

		h.mongoLoggerSvc.Error("[NotificationSvc.CreateAndSendNotification] Bulk notification sent successfully",
			zap.Int("recipient_count", len(recipients)),
			zap.String("type", string(req.Type)),
			zap.Int("status_code", fiber.StatusCreated),
			zap.Error(err),
			zap.Time("timestamp", time.Now()),
		)
		return c.Status(fiber.StatusCreated).JSON(fiber.Map{
			"message":          "Bulk notification sent successfully",
			"recipient_count":  len(recipients),
			"notification_ids": notificationIDs,
		})

	default:
		h.mongoLoggerSvc.Info("[NotificationSvc.CreateAndSendNotification] Invalid delivery scheme",
			zap.String("delivery_scheme", string(req.DeliveryScheme)),
			zap.Int("status_code", fiber.StatusBadRequest),
			zap.Time("timestamp", time.Now()),
		)
		return fiber.NewError(fiber.StatusBadRequest, "Invalid delivery scheme")
	}
}

func (h *Handler) GetUserNotification(c *fiber.Ctx) error {
	limitStr := c.Query("limit", "10")
	offsetStr := c.Query("offset", "0")

	// Convert limit and offset to integers
	limit, err := strconv.Atoi(limitStr)
	if err != nil || limit <= 0 {
		h.mongoLoggerSvc.Info("[NotificationSvc.GetUserNotification] Invalid limit value",
			zap.String("limit", limitStr),
			zap.Int("status_code", fiber.StatusBadRequest),
			zap.Error(err),
			zap.Time("timestamp", time.Now()),
		)
		return fiber.NewError(fiber.StatusBadRequest, "Invalid limit value")
	}
	offset, err := strconv.Atoi(offsetStr)
	if err != nil || offset < 0 {
		h.mongoLoggerSvc.Info("[NotificationSvc.GetUserNotification] Invalid offset value",
			zap.String("offset", offsetStr),
			zap.Int("status_code", fiber.StatusBadRequest),
			zap.Error(err),
			zap.Time("timestamp", time.Now()),
		)
		return fiber.NewError(fiber.StatusBadRequest, "Invalid offset value")
	}

	userID, ok := c.Locals("user_id").(int64)
	if !ok || userID == 0 {
		h.mongoLoggerSvc.Error("[NotificationSvc.GetUserNotification] Invalid user ID in context",
			zap.Int64("userID", userID),
			zap.Int("status_code", fiber.StatusInternalServerError),
			zap.Error(err),
			zap.Time("timestamp", time.Now()),
		)
		return fiber.NewError(fiber.StatusInternalServerError, "Invalid user identification")
	}

	notifications, total, err := h.notificationSvc.GetUserNotifications(context.Background(), userID, limit, offset)
	if err != nil {
		h.mongoLoggerSvc.Error("[NotificationSvc.GetUserNotification] Failed to fetch notifications",
			zap.Int64("userID", userID),
			zap.Int("status_code", fiber.StatusInternalServerError),
			zap.Error(err),
			zap.Time("timestamp", time.Now()),
		)
		return fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch notifications:"+err.Error())
	}

	return c.Status(fiber.StatusOK).JSON(fiber.Map{
		"notifications": notifications,
		"total_count":   total,
		"limit":         limit,
		"offset":        offset,
	})

}

// func (h *Handler) GetAllRecipientIDs(ctx context.Context, receiver domain.NotificationRecieverSide) ([]int64, error) {
// 	return h.notificationSvc.ListRecipientIDs(ctx, receiver)
// }

func (h *Handler) CountUnreadNotifications(c *fiber.Ctx) error {

	userID, ok := c.Locals("user_id").(int64)
	if !ok || userID == 0 {
		h.mongoLoggerSvc.Error("NotificationSvc.GetNotifications] Invalid user ID in context",
			zap.Int64("userID", userID),
			zap.Int("status_code", fiber.StatusInternalServerError),
			zap.Time("timestamp", time.Now()),
		)
		return fiber.NewError(fiber.StatusInternalServerError, "Invalid user identification")
	}

	total, err := h.notificationSvc.CountUnreadNotifications(c.Context(), userID)

	if err != nil {
		h.mongoLoggerSvc.Error("[NotificationSvc.CountUnreadNotifications] Failed to fetch unread notification count",
			zap.Int64("userID", userID),
			zap.Int("status_code", fiber.StatusInternalServerError),
			zap.Error(err),
			zap.Time("timestamp", time.Now()),
		)
		return fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch notifications:"+err.Error())
	}

	return c.Status(fiber.StatusOK).JSON(fiber.Map{
		"unread": total,
	})
}

func (h *Handler) GetAllNotifications(c *fiber.Ctx) error {
	limitStr := c.Query("limit", "10")
	pageStr := c.Query("page", "1")

	// Convert limit and offset to integers
	limit, err := strconv.Atoi(limitStr)
	if err != nil || limit <= 0 {
		h.mongoLoggerSvc.Info("[NotificationSvc.GetNotifications] Invalid limit value",
			zap.String("limit", limitStr),
			zap.Int("status_code", fiber.StatusBadRequest),
			zap.Error(err),
			zap.Time("timestamp", time.Now()),
		)
		return fiber.NewError(fiber.StatusBadRequest, "Invalid limit value")
	}
	page, err := strconv.Atoi(pageStr)
	if err != nil || page <= 0 {
		h.mongoLoggerSvc.Info("[NotificationSvc.GetNotifications] Invalid page value",
			zap.String("page", pageStr),
			zap.Int("status_code", fiber.StatusBadRequest),
			zap.Error(err),
			zap.Time("timestamp", time.Now()),
		)
		return fiber.NewError(fiber.StatusBadRequest, "Invalid page value")
	}

	notifications, err := h.notificationSvc.GetAllNotifications(context.Background(), limit, ((page - 1) * limit))
	if err != nil {
		h.mongoLoggerSvc.Error("[NotificationSvc.GetNotifications] Failed to fetch notifications",
			zap.Int64("limit", int64(limit)),
			zap.Int("status_code", fiber.StatusInternalServerError),
			zap.Error(err),
			zap.Time("timestamp", time.Now()),
		)
		return fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch notifications")
	}

	return c.Status(fiber.StatusOK).JSON(fiber.Map{
		"notifications": notifications,
		"total_count":   len(notifications),
		"limit":         limit,
		"page":          page,
	})

}

type SendSingleAfroSMSReq struct {
	Recipient string `json:"recipient" validate:"required" example:"+251912345678"`
	Message   string `json:"message" validate:"required" example:"Hello world"`
}

// SendSingleAfroSMS godoc
// @Summary Send single SMS via AfroMessage
// @Description Sends an SMS message to a single phone number using AfroMessage
// @Tags user
// @Accept json
// @Produce json
// @Param sendSMS body SendSingleAfroSMSReq true "Send SMS request"
// @Success 200 {object} response.APIResponse
// @Failure 400 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Router /api/v1/sendSMS [post]
func (h *Handler) SendSingleAfroSMS(c *fiber.Ctx) error {
	var req SendSingleAfroSMSReq

	if err := c.BodyParser(&req); err != nil {
		h.mongoLoggerSvc.Info("Failed to parse SendSingleAfroSMS request",
			zap.Int("status_code", fiber.StatusBadRequest),
			zap.Error(err),
			zap.Time("timestamp", time.Now()),
		)

		return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
			Message: "Failed to send SMS",
			Error:   "Invalid request body: " + err.Error(),
		})
	}

	// Validate request
	if valErrs, ok := h.validator.Validate(c, req); !ok {
		var errMsg string
		for field, msg := range valErrs {
			errMsg += fmt.Sprintf("%s: %s; ", field, msg)
		}

		return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
			Message: "Failed to send SMS",
			Error:   errMsg,
		})
	}

	// Send SMS via service
	if err := h.notificationSvc.SendAfroMessageSMS(
		c.Context(),
		req.Recipient,
		req.Message,
	); err != nil {

		h.mongoLoggerSvc.Error("Failed to send AfroMessage SMS",
			zap.String("phone_number", req.Recipient),
			zap.Int("status_code", fiber.StatusInternalServerError),
			zap.Error(err),
			zap.Time("timestamp", time.Now()),
		)

		return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{
			Message: "Failed to send SMS",
			Error:   err.Error(),
		})
	}

	return c.Status(fiber.StatusOK).JSON(domain.Response{
		Message:    "SMS sent successfully",
		Success:    true,
		StatusCode: fiber.StatusOK,
		Data:       req,
	})
}

func (h *Handler) RegisterDeviceToken(c *fiber.Ctx) error {
	type Request struct {
		DeviceToken string `json:"device_token" validate:"required"`
		Platform    string `json:"platform" validate:"required,oneof=android ios web"`
	}

	var req Request
	if err := c.BodyParser(&req); err != nil {
		h.mongoLoggerSvc.Info("[NotificationHandler.RegisterDeviceToken] Failed to parse request body",
			zap.Int("status_code", fiber.StatusBadRequest),
			zap.Error(err),
			zap.Time("timestamp", time.Now()),
		)
		return fiber.NewError(fiber.StatusBadRequest, "Invalid request body")
	}

	userID, ok := c.Locals("user_id").(int64)
	if !ok || userID == 0 {
		h.mongoLoggerSvc.Error("[NotificationHandler.RegisterDeviceToken] Invalid user ID in context",
			zap.Int("status_code", fiber.StatusUnauthorized),
			zap.Time("timestamp", time.Now()),
		)
		return fiber.NewError(fiber.StatusUnauthorized, "Invalid user identification")
	}

	if err := h.userSvc.RegisterDevice(c.Context(), userID, req.DeviceToken, req.Platform); err != nil {
		h.mongoLoggerSvc.Error("[NotificationHandler.RegisterDeviceToken] Failed to register device token",
			zap.Int64("userID", userID),
			zap.String("platform", req.Platform),
			zap.Int("status_code", fiber.StatusInternalServerError),
			zap.Error(err),
			zap.Time("timestamp", time.Now()),
		)
		return fiber.NewError(fiber.StatusInternalServerError, "Failed to register device token: "+err.Error())
	}

	h.mongoLoggerSvc.Info("[NotificationHandler.RegisterDeviceToken] Device token registered successfully",
		zap.Int64("userID", userID),
		zap.String("platform", req.Platform),
		zap.Time("timestamp", time.Now()),
	)

	return c.Status(fiber.StatusCreated).JSON(domain.Response{
		Message:    "Device token registered successfully",
		Success:    true,
		StatusCode: fiber.StatusCreated,
	})
}

// SendTestPushNotification sends a test push notification to the authenticated user
// @Summary Send test push notification
// @Description Sends a test push notification to all registered devices of the current user
// @Tags notifications
// @Accept json
// @Produce json
// @Param body body object{title=string,message=string} true "Test notification content"
// @Success 200 {object} domain.Response
// @Failure 400 {object} domain.ErrorResponse
// @Failure 401 {object} domain.ErrorResponse
// @Failure 500 {object} domain.ErrorResponse
// @Router /api/v1/notifications/test-push [post]
func (h *Handler) SendTestPushNotification(c *fiber.Ctx) error {
	type Request struct {
		Title   string `json:"title"`
		Message string `json:"message"`
	}

	var req Request
	if err := c.BodyParser(&req); err != nil {
		return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
			Message: "Invalid request body",
			Error:   err.Error(),
		})
	}

	if req.Title == "" {
		req.Title = "Test Push Notification"
	}
	if req.Message == "" {
		req.Message = "This is a test push notification from Yimaru Backend"
	}

	userID, ok := c.Locals("user_id").(int64)
	if !ok || userID == 0 {
		return c.Status(fiber.StatusUnauthorized).JSON(domain.ErrorResponse{
			Message: "Invalid user identification",
			Error:   "User ID not found in context",
		})
	}

	// Get user's device tokens first to provide feedback
	tokens, err := h.userSvc.GetUserDeviceTokens(c.Context(), userID)
	if err != nil {
		return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{
			Message: "Failed to get device tokens",
			Error:   err.Error(),
		})
	}

	if len(tokens) == 0 {
		return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
			Message: "No registered devices found",
			Error:   "Please register a device token first using POST /devices/register",
		})
	}

	// Create test notification
	notification := &domain.Notification{
		RecipientID:     userID,
		Type:            "system_alert",
		DeliveryChannel: domain.DeliveryChannelPush,
		Payload: domain.NotificationPayload{
			Headline: req.Title,
			Message:  req.Message,
		},
	}

	// Send push notification
	err = h.notificationSvc.SendPushNotification(c.Context(), notification)
	if err != nil {
		return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{
			Message: "Failed to send push notification",
			Error:   err.Error(),
		})
	}

	h.mongoLoggerSvc.Info("[NotificationHandler.SendTestPushNotification] Test push sent",
		zap.Int64("userID", userID),
		zap.Int("deviceCount", len(tokens)),
		zap.Time("timestamp", time.Now()),
	)

	return c.Status(fiber.StatusOK).JSON(domain.Response{
		Message:    "Test push notification sent successfully",
		Success:    true,
		StatusCode: fiber.StatusOK,
		Data: map[string]interface{}{
			"devices_count": len(tokens),
			"title":         req.Title,
			"message":       req.Message,
		},
	})
}

func (h *Handler) UnregisterDeviceToken(c *fiber.Ctx) error {
	type Request struct {
		DeviceToken string `json:"device_token" validate:"required"`
	}

	var req Request
	if err := c.BodyParser(&req); err != nil {
		h.mongoLoggerSvc.Info("[NotificationHandler.UnregisterDeviceToken] Failed to parse request body",
			zap.Int("status_code", fiber.StatusBadRequest),
			zap.Error(err),
			zap.Time("timestamp", time.Now()),
		)
		return fiber.NewError(fiber.StatusBadRequest, "Invalid request body")
	}

	userID, ok := c.Locals("user_id").(int64)
	if !ok || userID == 0 {
		h.mongoLoggerSvc.Error("[NotificationHandler.UnregisterDeviceToken] Invalid user ID in context",
			zap.Int("status_code", fiber.StatusUnauthorized),
			zap.Time("timestamp", time.Now()),
		)
		return fiber.NewError(fiber.StatusUnauthorized, "Invalid user identification")
	}

	if err := h.userSvc.DeactivateDevice(c.Context(), userID, req.DeviceToken); err != nil {
		h.mongoLoggerSvc.Error("[NotificationHandler.UnregisterDeviceToken] Failed to unregister device token",
			zap.Int64("userID", userID),
			zap.Int("status_code", fiber.StatusInternalServerError),
			zap.Error(err),
			zap.Time("timestamp", time.Now()),
		)
		return fiber.NewError(fiber.StatusInternalServerError, "Failed to unregister device token: "+err.Error())
	}

	h.mongoLoggerSvc.Info("[NotificationHandler.UnregisterDeviceToken] Device token unregistered successfully",
		zap.Int64("userID", userID),
		zap.Time("timestamp", time.Now()),
	)

	return c.Status(fiber.StatusOK).JSON(domain.Response{
		Message:    "Device token unregistered successfully",
		Success:    true,
		StatusCode: fiber.StatusOK,
	})
}
