<?php
/**
 * Notification Service
 * 
 * This service provides methods to create and manage notifications
 */

class NotificationService {
    private $db;

    public function __construct() {
        require_once __DIR__ . '/../config/database.php';
        $this->db = new Database();
    }

    /**
     * Create a new notification
     *
     * @param array $data Notification data
     * @return array Result with success status and notification ID
     */
    public function createNotification($data) {
        try {
            $conn = $this->db->getConnection();
            
            // Start transaction
            $conn->beginTransaction();
            
            // Insert notification
            $query = "INSERT INTO notifications 
                      (type, title, message, target_audience, target_user_id, created_by, priority, expires_at, related_entity_type, related_entity_id, metadata) 
                      VALUES 
                      (:type, :title, :message, :target_audience, :target_user_id, :created_by, :priority, :expires_at, :related_entity_type, :related_entity_id, :metadata)";
            
            $stmt = $conn->prepare($query);
            $stmt->bindValue(':type', $data['type']);
            $stmt->bindValue(':title', $data['title']);
            $stmt->bindValue(':message', $data['message']);
            $stmt->bindValue(':target_audience', $data['target_audience']);
            $stmt->bindValue(':target_user_id', isset($data['target_user_id']) ? $data['target_user_id'] : null);
            $stmt->bindValue(':created_by', $data['created_by']);
            $stmt->bindValue(':priority', isset($data['priority']) ? $data['priority'] : 'normal');
            $stmt->bindValue(':expires_at', isset($data['expires_at']) ? $data['expires_at'] : null);
            $stmt->bindValue(':related_entity_type', isset($data['related_entity_type']) ? $data['related_entity_type'] : null);
            $stmt->bindValue(':related_entity_id', isset($data['related_entity_id']) ? $data['related_entity_id'] : null);
            $stmt->bindValue(':metadata', isset($data['metadata']) ? json_encode($data['metadata']) : null);
            $stmt->execute();
            
            $notificationId = $conn->lastInsertId();
            
            // Create recipients based on target audience
            $recipients = [];
            
            if ($data['target_audience'] === 'all' || $data['target_audience'] === 'admins') {
                // Add all admins
                $adminQuery = "SELECT id FROM admins WHERE status = 'active'";
                $adminStmt = $conn->query($adminQuery);
                while ($admin = $adminStmt->fetch(PDO::FETCH_ASSOC)) {
                    $recipients[] = [
                        'user_id' => $admin['id'],
                        'user_type' => 'admin'
                    ];
                }
            }
            
            if ($data['target_audience'] === 'all' || $data['target_audience'] === 'members') {
                // Add all members
                $memberQuery = "SELECT id FROM members WHERE status = 'active'";
                $memberStmt = $conn->query($memberQuery);
                while ($member = $memberStmt->fetch(PDO::FETCH_ASSOC)) {
                    $recipients[] = [
                        'user_id' => $member['id'],
                        'user_type' => 'member'
                    ];
                }
            }
            
            if ($data['target_audience'] === 'specific' && isset($data['target_user_id'])) {
                // Add specific user
                $user_type = isset($data['user_type']) ? $data['user_type'] : 'member';
                $recipients[] = [
                    'user_id' => $data['target_user_id'],
                    'user_type' => $user_type
                ];
            }
            
            // Insert recipients
            if (!empty($recipients)) {
                $recipientQuery = "INSERT INTO notification_recipients (notification_id, user_id, user_type) VALUES (:notification_id, :user_id, :user_type)";
                $recipientStmt = $conn->prepare($recipientQuery);
                
                foreach ($recipients as $recipient) {
                    $recipientStmt->bindValue(':notification_id', $notificationId);
                    $recipientStmt->bindValue(':user_id', $recipient['user_id']);
                    $recipientStmt->bindValue(':user_type', $recipient['user_type']);
                    $recipientStmt->execute();
                }
            }
            
            // Commit transaction
            $conn->commit();
            
            // Trigger WebSocket notification if enabled
            $this->triggerRealTimeNotification($notificationId, $recipients);
            
            return [
                'success' => true,
                'notification_id' => $notificationId,
                'recipient_count' => count($recipients)
            ];
            
        } catch (Exception $e) {
            // Rollback transaction on error
            if (isset($conn)) {
                $conn->rollBack();
            }
            
            return [
                'success' => false,
                'message' => $e->getMessage()
            ];
        }
    }

    /**
     * Mark a notification as read for a user
     *
     * @param int $notificationId Notification ID
     * @param int $userId User ID
     * @param string $userType User type (admin or member)
     * @return array Result with success status
     */
    public function markAsRead($notificationId, $userId, $userType) {
        try {
            $conn = $this->db->getConnection();
            
            // Check if record exists
            $checkQuery = "SELECT id FROM notification_recipients 
                          WHERE notification_id = :notification_id 
                          AND user_id = :user_id 
                          AND user_type = :user_type";
            $checkStmt = $conn->prepare($checkQuery);
            $checkStmt->bindValue(':notification_id', $notificationId);
            $checkStmt->bindValue(':user_id', $userId);
            $checkStmt->bindValue(':user_type', $userType);
            $checkStmt->execute();
            
            if ($checkStmt->rowCount() > 0) {
                // Update existing record
                $query = "UPDATE notification_recipients 
                          SET is_read = 1, read_at = NOW() 
                          WHERE notification_id = :notification_id 
                          AND user_id = :user_id 
                          AND user_type = :user_type";
                $stmt = $conn->prepare($query);
                $stmt->bindValue(':notification_id', $notificationId);
                $stmt->bindValue(':user_id', $userId);
                $stmt->bindValue(':user_type', $userType);
                $stmt->execute();
            } else {
                // Insert new record
                $query = "INSERT INTO notification_recipients 
                          (notification_id, user_id, user_type, is_read, read_at) 
                          VALUES 
                          (:notification_id, :user_id, :user_type, 1, NOW())";
                $stmt = $conn->prepare($query);
                $stmt->bindValue(':notification_id', $notificationId);
                $stmt->bindValue(':user_id', $userId);
                $stmt->bindValue(':user_type', $userType);
                $stmt->execute();
            }
            
            // Check if all recipients have read this notification
            $allReadQuery = "SELECT 
                              (SELECT COUNT(*) FROM notification_recipients WHERE notification_id = :notification_id) as total,
                              (SELECT COUNT(*) FROM notification_recipients WHERE notification_id = :notification_id AND is_read = 1) as read_count";
            $allReadStmt = $conn->prepare($allReadQuery);
            $allReadStmt->bindValue(':notification_id', $notificationId);
            $allReadStmt->execute();
            $readStats = $allReadStmt->fetch(PDO::FETCH_ASSOC);
            
            // If all recipients have read, update the main notification
            if ($readStats['total'] > 0 && $readStats['total'] == $readStats['read_count']) {
                $updateNotificationQuery = "UPDATE notifications 
                                          SET is_read = 1, read_at = NOW() 
                                          WHERE id = :notification_id";
                $updateNotificationStmt = $conn->prepare($updateNotificationQuery);
                $updateNotificationStmt->bindValue(':notification_id', $notificationId);
                $updateNotificationStmt->execute();
            }
            
            return [
                'success' => true
            ];
            
        } catch (Exception $e) {
            return [
                'success' => false,
                'message' => $e->getMessage()
            ];
        }
    }

    /**
     * Get unread notification count for a user
     *
     * @param int $userId User ID
     * @param string $userType User type (admin or member)
     * @return int Unread notification count
     */
    public function getUnreadCount($userId, $userType) {
        try {
            $conn = $this->db->getConnection();
            
            $query = "SELECT COUNT(*) as unread_count
                      FROM notification_recipients
                      WHERE user_id = :user_id 
                      AND user_type = :user_type
                      AND is_read = 0";
            
            $stmt = $conn->prepare($query);
            $stmt->bindValue(':user_id', $userId);
            $stmt->bindValue(':user_type', $userType);
            $stmt->execute();
            
            return $stmt->fetch(PDO::FETCH_ASSOC)['unread_count'];
            
        } catch (Exception $e) {
            return 0;
        }
    }

    /**
     * Get recent notifications for a user
     *
     * @param int $userId User ID
     * @param string $userType User type (admin or member)
     * @param int $limit Maximum number of notifications to return
     * @return array Notifications
     */
    public function getRecentNotifications($userId, $userType, $limit = 10) {
        try {
            $conn = $this->db->getConnection();
            
            $query = "SELECT 
                        n.id, n.type, n.title, n.message, n.priority, n.created_at,
                        CONCAT(a.first_name, ' ', a.last_name) as created_by_name,
                        nr.is_read, nr.read_at
                      FROM notifications n
                      JOIN notification_recipients nr ON n.id = nr.notification_id
                      LEFT JOIN admins a ON n.created_by = a.id
                      WHERE nr.user_id = :user_id 
                      AND nr.user_type = :user_type
                      ORDER BY n.created_at DESC
                      LIMIT :limit";
            
            $stmt = $conn->prepare($query);
            $stmt->bindValue(':user_id', $userId);
            $stmt->bindValue(':user_type', $userType);
            $stmt->bindValue(':limit', $limit, PDO::PARAM_INT);
            $stmt->execute();
            
            return $stmt->fetchAll(PDO::FETCH_ASSOC);
            
        } catch (Exception $e) {
            return [];
        }
    }

    /**
     * Delete old notifications based on settings
     *
     * @return int Number of deleted notifications
     */
    public function cleanupOldNotifications() {
        try {
            $conn = $this->db->getConnection();
            
            // Get cleanup days from settings
            $settingQuery = "SELECT setting_value FROM settings WHERE setting_key = 'notification_cleanup_days'";
            $settingStmt = $conn->query($settingQuery);
            $cleanupDays = 30; // Default to 30 days
            
            if ($settingStmt->rowCount() > 0) {
                $cleanupDays = (int)$settingStmt->fetch(PDO::FETCH_ASSOC)['setting_value'];
            }
            
            // Get notifications to delete
            $getQuery = "SELECT id FROM notifications WHERE created_at < DATE_SUB(NOW(), INTERVAL :days DAY)";
            $getStmt = $conn->prepare($getQuery);
            $getStmt->bindValue(':days', $cleanupDays);
            $getStmt->execute();
            
            $notificationIds = $getStmt->fetchAll(PDO::FETCH_COLUMN);
            
            if (empty($notificationIds)) {
                return 0;
            }
            
            // Delete recipients first
            $recipientQuery = "DELETE FROM notification_recipients WHERE notification_id IN (" . implode(',', $notificationIds) . ")";
            $conn->exec($recipientQuery);
            
            // Delete notifications
            $notificationQuery = "DELETE FROM notifications WHERE id IN (" . implode(',', $notificationIds) . ")";
            $conn->exec($notificationQuery);
            
            return count($notificationIds);
            
        } catch (Exception $e) {
            error_log("Error cleaning up notifications: " . $e->getMessage());
            return 0;
        }
    }

    /**
     * Trigger real-time notification via WebSocket
     *
     * @param int $notificationId Notification ID
     * @param array $recipients Recipients list
     */
    private function triggerRealTimeNotification($notificationId, $recipients) {
        try {
            // Get notification details
            $conn = $this->db->getConnection();
            
            $query = "SELECT 
                        n.id, n.type, n.title, n.message, n.priority, n.created_at,
                        CONCAT(a.first_name, ' ', a.last_name) as created_by_name,
                        n.related_entity_type, n.related_entity_id
                      FROM notifications n
                      LEFT JOIN admins a ON n.created_by = a.id
                      WHERE n.id = :notification_id";
            
            $stmt = $conn->prepare($query);
            $stmt->bindValue(':notification_id', $notificationId);
            $stmt->execute();
            
            if ($stmt->rowCount() === 0) {
                return;
            }
            
            $notification = $stmt->fetch(PDO::FETCH_ASSOC);
            
            // Check if real-time notifications are enabled
            $settingQuery = "SELECT setting_value FROM settings WHERE setting_key = 'notification_system_enabled'";
            $settingStmt = $conn->query($settingQuery);
            
            if ($settingStmt->rowCount() > 0 && $settingStmt->fetch(PDO::FETCH_ASSOC)['setting_value'] == '1') {
                // Here you would trigger a WebSocket event
                // For now, we'll just log this
                error_log("Real-time notification triggered: " . json_encode($notification));
                
                // In a production environment, you might use a message queue or direct WebSocket connection
                // Example: 
                // $socket = new WebSocket('ws://localhost:8080');
                // $socket->send(json_encode([
                //     'action' => 'send_notification',
                //     'notification' => $notification,
                //     'recipients' => $recipients
                // ]));
            }
        } catch (Exception $e) {
            error_log("Error triggering real-time notification: " . $e->getMessage());
        }
    }
}
