<?php

use Minishlink\WebPush\WebPush;
use Minishlink\WebPush\Subscription;

/**
 * NotificationService
 * Handles push notification delivery
 */
class NotificationService {
    
    private $webPush;
    private $notificationModel;
    private $contactModel;
    private $noteModel;
    
    public function __construct() {
        // Initialize WebPush with VAPID keys
        $auth = [
            'VAPID' => [
                'subject' => VAPID_SUBJECT,
                'publicKey' => VAPID_PUBLIC_KEY,
                'privateKey' => VAPID_PRIVATE_KEY,
            ]
        ];
        
        $this->webPush = new WebPush($auth);
        $this->notificationModel = new NotificationSubscription();
        $this->contactModel = new Contact();
        $this->noteModel = new Note();
    }
    
    /**
     * Send push notification to a specific user
     * 
     * @param int $userId User ID
     * @param array $payload Notification payload
     * @return array Results of notification delivery
     */
    public function sendToUser($userId, $payload) {
        try {
            $subscriptions = $this->notificationModel->getByUser($userId);
            
            if (empty($subscriptions)) {
                logError("No subscriptions found for user ID: $userId");
                return [
                    'success' => false,
                    'sent' => 0,
                    'failed' => 0,
                    'error' => 'No subscriptions found'
                ];
            }
            
            $results = [
                'success' => true,
                'sent' => 0,
                'failed' => 0,
                'errors' => []
            ];
            
            foreach ($subscriptions as $sub) {
                $result = $this->sendNotification($sub, $payload);
                
                if ($result['success']) {
                    $results['sent']++;
                } else {
                    $results['failed']++;
                    $results['errors'][] = [
                        'subscription_id' => $sub['id'],
                        'error' => $result['error']
                    ];
                }
            }
            
            return $results;
        } catch (Exception $e) {
            logError('Failed to send notification to user: ' . $e->getMessage());
            return [
                'success' => false,
                'sent' => 0,
                'failed' => 0,
                'error' => $e->getMessage()
            ];
        }
    }
    
    /**
     * Send push notification to all users
     * 
     * @param array $payload Notification payload
     * @return array Results of notification delivery
     */
    public function sendToAll($payload) {
        try {
            $subscriptions = $this->notificationModel->getAllActive();
            
            if (empty($subscriptions)) {
                logError('No active subscriptions found');
                return [
                    'success' => false,
                    'sent' => 0,
                    'failed' => 0,
                    'error' => 'No active subscriptions'
                ];
            }
            
            $results = [
                'success' => true,
                'sent' => 0,
                'failed' => 0,
                'errors' => []
            ];
            
            foreach ($subscriptions as $sub) {
                $result = $this->sendNotification($sub, $payload);
                
                if ($result['success']) {
                    $results['sent']++;
                } else {
                    $results['failed']++;
                    $results['errors'][] = [
                        'subscription_id' => $sub['id'],
                        'user_id' => $sub['user_id'],
                        'error' => $result['error']
                    ];
                }
            }
            
            return $results;
        } catch (Exception $e) {
            logError('Failed to send notifications to all users: ' . $e->getMessage());
            return [
                'success' => false,
                'sent' => 0,
                'failed' => 0,
                'error' => $e->getMessage()
            ];
        }
    }
    
    /**
     * Send notification to a single subscription
     * 
     * @param array $subscriptionData Subscription data from database
     * @param array $payload Notification payload
     * @return array Result of notification delivery
     */
    private function sendNotification($subscriptionData, $payload) {
        try {
            // Create subscription object
            $subscription = Subscription::create([
                'endpoint' => $subscriptionData['endpoint'],
                'keys' => [
                    'p256dh' => $subscriptionData['p256dh_key'],
                    'auth' => $subscriptionData['auth_key']
                ]
            ]);
            
            // Send notification
            $report = $this->webPush->sendOneNotification(
                $subscription,
                json_encode($payload)
            );
            
            // Check if successful
            if ($report->isSuccess()) {
                return [
                    'success' => true,
                    'subscription_id' => $subscriptionData['id']
                ];
            } else {
                $error = $report->getReason();
                logError("Notification failed for subscription {$subscriptionData['id']}: $error");
                
                // If subscription is expired or invalid, delete it
                if ($report->isSubscriptionExpired()) {
                    $this->notificationModel->delete(
                        $subscriptionData['user_id'],
                        $subscriptionData['endpoint']
                    );
                    logError("Deleted expired subscription {$subscriptionData['id']}");
                }
                
                return [
                    'success' => false,
                    'subscription_id' => $subscriptionData['id'],
                    'error' => $error
                ];
            }
        } catch (Exception $e) {
            logError('Failed to send notification: ' . $e->getMessage());
            return [
                'success' => false,
                'subscription_id' => $subscriptionData['id'] ?? null,
                'error' => $e->getMessage()
            ];
        }
    }
    
    /**
     * Generate notification payload for daily reminders
     * 
     * @param int $userId User ID
     * @return array Notification payload
     */
    public function generateDailyReminderPayload($userId) {
        try {
            logError("Generating payload for user $userId");

            // Get today's birthdays
            $birthdays = $this->contactModel->getTodayBirthdays($userId);
            logError("User $userId: Found " . count($birthdays) . " birthdays today");

            // Get today's notes
            $notes = $this->noteModel->getTodayNotes($userId);
            logError("User $userId: Found " . count($notes) . " notes/reminders today");

            $birthdayCount = count($birthdays);
            $noteCount = count($notes);
            $totalCount = $birthdayCount + $noteCount;

            if ($totalCount === 0) {
                logError("User $userId: No reminders today, returning null");
                return null; // No reminders for today
            }

            // Generate message
            $message = '';
            if ($birthdayCount > 0 && $noteCount > 0) {
                $message = "You have $birthdayCount birthday" . ($birthdayCount > 1 ? 's' : '') .
                          " and $noteCount reminder" . ($noteCount > 1 ? 's' : '') . " today!";
            } elseif ($birthdayCount > 0) {
                $message = "You have $birthdayCount birthday" . ($birthdayCount > 1 ? 's' : '') . " today!";
            } else {
                $message = "You have $noteCount reminder" . ($noteCount > 1 ? 's' : '') . " today!";
            }

            logError("User $userId: Generated message: $message");

            // Create payload with relative URLs for PWA compatibility
            $payload = [
                'title' => 'Birthday Reminder',
                'body' => $message,
                'icon' => URL_PATH . '/public/images/icons/icon-192x192.png',
                'badge' => URL_PATH . '/public/images/icons/icon-72x72.png',
                'tag' => 'daily-reminder-' . date('Y-m-d'),
                'requireInteraction' => true,
                'data' => [
                    'url' => URL_PATH . '/home',
                    'birthdayCount' => $birthdayCount,
                    'noteCount' => $noteCount,
                    'date' => date('Y-m-d')
                ],
                'actions' => [
                    [
                        'action' => 'view',
                        'title' => 'View Reminders'
                    ],
                    [
                        'action' => 'close',
                        'title' => 'Dismiss'
                    ]
                ]
            ];

            return $payload;
        } catch (Exception $e) {
            logError('Failed to generate daily reminder payload for user ' . $userId . ': ' . $e->getMessage());
            return null;
        }
    }
    
    /**
     * Send daily reminders to all users with birthdays/notes today
     * 
     * @return array Results of notification delivery
     */
    public function sendDailyReminders() {
        try {
            logError('=== sendDailyReminders() called ===');

            $subscriptions = $this->notificationModel->getAllActive();
            logError('Active subscriptions count: ' . count($subscriptions));

            if (empty($subscriptions)) {
                logError('No active subscriptions for daily reminders');
                return [
                    'success' => false,
                    'sent' => 0,
                    'skipped' => 0,
                    'failed' => 0,
                    'error' => 'No active subscriptions'
                ];
            }

            $results = [
                'success' => true,
                'sent' => 0,
                'skipped' => 0,
                'failed' => 0,
                'errors' => []
            ];

            // Group subscriptions by user
            $userSubscriptions = [];
            foreach ($subscriptions as $sub) {
                $userId = $sub['user_id'];
                if (!isset($userSubscriptions[$userId])) {
                    $userSubscriptions[$userId] = [];
                }
                $userSubscriptions[$userId][] = $sub;
            }

            logError('Total users with subscriptions: ' . count($userSubscriptions));

            // Send notifications to each user
            foreach ($userSubscriptions as $userId => $subs) {
                logError("Processing user ID: $userId (has " . count($subs) . " subscription(s))");

                // Generate payload for this user
                $payload = $this->generateDailyReminderPayload($userId);

                if ($payload === null) {
                    // No reminders for this user today, skip
                    logError("User $userId has no reminders today, skipping " . count($subs) . " subscription(s)");
                    $results['skipped'] += count($subs);
                    continue;
                }

                logError("User $userId has reminders, sending notifications...", ['payload' => $payload]);

                // Send to all subscriptions for this user
                foreach ($subs as $sub) {
                    logError("Sending notification to subscription ID: {$sub['id']}");
                    $result = $this->sendNotification($sub, $payload);

                    if ($result['success']) {
                        logError("Successfully sent to subscription {$sub['id']}");
                        $results['sent']++;
                    } else {
                        logError("Failed to send to subscription {$sub['id']}: {$result['error']}");
                        $results['failed']++;
                        $results['errors'][] = [
                            'subscription_id' => $sub['id'],
                            'user_id' => $userId,
                            'error' => $result['error']
                        ];
                    }
                }
            }

            // Log results
            logError("=== Daily reminders complete ===");
            logError("Sent: {$results['sent']}, Skipped: {$results['skipped']}, Failed: {$results['failed']}");

            if (!empty($results['errors'])) {
                logError("Errors encountered:", $results['errors']);
            }

            return $results;
        } catch (Exception $e) {
            logError('=== EXCEPTION in sendDailyReminders ===');
            logError('Error: ' . $e->getMessage());
            logError('Trace: ' . $e->getTraceAsString());
            return [
                'success' => false,
                'sent' => 0,
                'skipped' => 0,
                'failed' => 0,
                'error' => $e->getMessage()
            ];
        }
    }
    
    /**
     * Test notification delivery
     * 
     * @param int $userId User ID
     * @param string $message Optional custom message
     * @return bool Success status
     */
    public function sendTestNotification($userId, $message = null) {
        $payload = [
            'title' => 'Test Notification',
            'body' => $message ?? 'This is a test notification from Birthday Reminder PWA',
            'icon' => URL_PATH . '/public/images/icons/icon-192x192.png',
            'badge' => URL_PATH . '/public/images/icons/icon-72x72.png',
            'tag' => 'test-notification',
            'data' => [
                'url' => URL_PATH . '/home',
                'test' => true
            ]
        ];

        $result = $this->sendToUser($userId, $payload);
        return $result['sent'] > 0;
    }
    
    /**
     * Get service status
     * 
     * @return array Service status information
     */
    public function getStatus() {
        try {
            $vapidConfigured = defined('VAPID_PUBLIC_KEY') && 
                              defined('VAPID_PRIVATE_KEY') && 
                              !empty(VAPID_PUBLIC_KEY) && 
                              !empty(VAPID_PRIVATE_KEY);
            
            $serviceAvailable = class_exists('Minishlink\WebPush\WebPush');
            
            $subscriptions = $this->notificationModel->getAllActive();
            $totalSubscriptions = count($subscriptions);
            
            return [
                'vapid_configured' => $vapidConfigured,
                'service_available' => $serviceAvailable,
                'total_subscriptions' => $totalSubscriptions
            ];
        } catch (Exception $e) {
            logError('Failed to get service status: ' . $e->getMessage());
            return [
                'vapid_configured' => false,
                'service_available' => false,
                'total_subscriptions' => 0,
                'error' => $e->getMessage()
            ];
        }
    }
    
    /**
     * Send daily notifications to all users
     * 
     * @return array Statistics about notifications sent
     */
    public function sendDailyNotifications() {
        try {
            $subscriptions = $this->notificationModel->getAllActive();
            
            $stats = [
                'total_users' => 0,
                'users_with_reminders' => 0,
                'notifications_sent' => 0,
                'notifications_failed' => 0,
                'users_without_subscriptions' => 0
            ];
            
            if (empty($subscriptions)) {
                $stats['error'] = 'No active subscriptions';
                return $stats;
            }
            
            // Group subscriptions by user
            $userSubscriptions = [];
            foreach ($subscriptions as $sub) {
                $userId = $sub['user_id'];
                if (!isset($userSubscriptions[$userId])) {
                    $userSubscriptions[$userId] = [];
                }
                $userSubscriptions[$userId][] = $sub;
            }
            
            $stats['total_users'] = count($userSubscriptions);
            
            // Send notifications to each user
            foreach ($userSubscriptions as $userId => $subs) {
                // Generate payload for this user
                $payload = $this->generateDailyReminderPayload($userId);
                
                if ($payload === null) {
                    // No reminders for this user today, skip
                    continue;
                }
                
                $stats['users_with_reminders']++;
                
                // Send to all subscriptions for this user
                foreach ($subs as $sub) {
                    $result = $this->sendNotification($sub, $payload);
                    
                    if ($result['success']) {
                        $stats['notifications_sent']++;
                    } else {
                        $stats['notifications_failed']++;
                    }
                }
            }
            
            return $stats;
        } catch (Exception $e) {
            logError('Failed to send daily notifications: ' . $e->getMessage());
            return [
                'total_users' => 0,
                'users_with_reminders' => 0,
                'notifications_sent' => 0,
                'notifications_failed' => 0,
                'users_without_subscriptions' => 0,
                'error' => $e->getMessage()
            ];
        }
    }
    
    /**
     * Generate notification payload for a user
     * Alias for generateDailyReminderPayload for backward compatibility
     * 
     * @param int $userId User ID
     * @return array|null Notification payload
     */
    public function generateNotificationPayload($userId) {
        return $this->generateDailyReminderPayload($userId);
    }
    
    /**
     * Send push notification to a subscription
     * 
     * @param array $subscription Subscription data
     * @param array $payload Notification payload
     * @return bool Success status
     */
    public function sendPushNotification($subscription, $payload) {
        $result = $this->sendNotification($subscription, $payload);
        return $result['success'];
    }
}

