PushNotificationService.java 6.08 KB
package com.ecommerce.notification.service;

import com.ecommerce.notification.model.Notification;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.util.HashMap;
import java.util.Map;

@Slf4j
@Service
@RequiredArgsConstructor
public class PushNotificationService {
    
    private final RestTemplate restTemplate;
    private final TemplateService templateService;
    
    @Value("${fcm.server-key:default-key}")
    private String fcmServerKey;
    
    @Value("${fcm.url:https://fcm.googleapis.com/fcm/send}")
    private String fcmUrl;
    
    public boolean sendPushNotification(Notification notification) {
        try {
            String title = notification.getSubject() != null ? 
                    notification.getSubject() : "Notification";
            String body = notification.getContent();
            
            // Process template if provided
            if (notification.getTemplateName() != null) {
                Map<String, Object> templateResult = templateService.processTemplate(
                        notification.getTemplateName(), 
                        "PUSH", 
                        new HashMap<>()
                );
                body = (String) templateResult.get("content");
                if (templateResult.containsKey("subject")) {
                    title = (String) templateResult.get("subject");
                }
            }
            
            return sendViaFcm(notification.getDeviceToken(), title, body, notification.getMetadata());
            
        } catch (Exception e) {
            log.error("Failed to send push notification to {}: {}", 
                    notification.getDeviceToken(), e.getMessage());
            return false;
        }
    }
    
    private boolean sendViaFcm(String deviceToken, String title, String body, Map<String, Object> data) {
        try {
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON);
            headers.set("Authorization", "key=" + fcmServerKey);
            
            Map<String, Object> message = new HashMap<>();
            message.put("to", deviceToken);
            
            Map<String, Object> notification = new HashMap<>();
            notification.put("title", title);
            notification.put("body", body);
            notification.put("sound", "default");
            
            message.put("notification", notification);
            
            if (data != null && !data.isEmpty()) {
                message.put("data", data);
            }
            
            Map<String, Object> android = new HashMap<>();
            Map<String, Object> androidNotification = new HashMap<>();
            androidNotification.put("sound", "default");
            androidNotification.put("priority", "high");
            android.put("notification", androidNotification);
            message.put("android", android);
            
            Map<String, Object> apns = new HashMap<>();
            Map<String, Object> apnsPayload = new HashMap<>();
            Map<String, Object> aps = new HashMap<>();
            aps.put("sound", "default");
            aps.put("badge", 1);
            apnsPayload.put("aps", aps);
            apns.put("payload", apnsPayload);
            message.put("apns", apns);
            
            HttpEntity<Map<String, Object>> request = new HttpEntity<>(message, headers);
            ResponseEntity<Map> response = restTemplate.postForEntity(fcmUrl, request, Map.class);
            
            boolean success = response.getStatusCode().is2xxSuccessful();
            if (success) {
                log.info("FCM push notification sent successfully to: {}", deviceToken);
            } else {
                log.error("FCM API error: {}", response.getBody());
            }
            
            return success;
            
        } catch (Exception e) {
            log.error("FCM push notification sending failed: {}", e.getMessage());
            return simulatePushNotification(deviceToken, title, body);
        }
    }
    
    private boolean simulatePushNotification(String deviceToken, String title, String body) {
        try {
            // Simulate push notification with 90% success rate
            boolean success = Math.random() > 0.1;
            
            if (success) {
                log.info("Push notification simulated successfully to {}: {} - {}", 
                        deviceToken, title, body);
            } else {
                log.warn("Push notification simulation failed to: {}", deviceToken);
            }
            
            return success;
            
        } catch (Exception e) {
            log.error("Push notification simulation failed: {}", e.getMessage());
            return false;
        }
    }
    
    public boolean subscribeToTopic(String deviceToken, String topic) {
        try {
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON);
            headers.set("Authorization", "key=" + fcmServerKey);
            
            Map<String, Object> requestBody = new HashMap<>();
            requestBody.put("to", "/topics/" + topic);
            requestBody.put("registration_tokens", new String[]{deviceToken});
            
            String subscribeUrl = "https://iid.googleapis.com/iid/v1:batchAdd";
            HttpEntity<Map<String, Object>> request = new HttpEntity<>(requestBody, headers);
            ResponseEntity<Map> response = restTemplate.postForEntity(subscribeUrl, request, Map.class);
            
            boolean success = response.getStatusCode().is2xxSuccessful();
            if (success) {
                log.info("Device {} subscribed to topic: {}", deviceToken, topic);
            }
            
            return success;
            
        } catch (Exception e) {
            log.error("Failed to subscribe device to topic: {}", e.getMessage());
            return false;
        }
    }
}