<?php
/**
 * Notification Manager Class
 * Handles SMS and Email notifications for various events
 */

class NotificationManager {
    private $conn;
    private $smsConfig;
    private $emailConfig;
    
    public function __construct($connection) {
        $this->conn = $connection;
        $this->loadConfigurations();
    }
    
    /**
     * Load SMS and Email configurations from database
     */
    private function loadConfigurations() {
        // Default SMS Configuration
        $defaultSmsConfig = [
            'enabled' => false,
            'provider' => 'generic',
            'api_url' => '',
            'api_key' => '',
            'sender_id' => '',
            'username' => '',
            'password' => '',
            'account_sid' => '',
            'auth_token' => '',
            'from_number' => '',
            'phone_number' => ''
        ];
        
        // Default Email Configuration
        $defaultEmailConfig = [
            'enabled' => false,
            'smtp_host' => '',
            'smtp_port' => 587,
            'smtp_username' => '',
            'smtp_password' => '',
            'from_email' => '',
            'from_name' => 'D-Bundles Stores'
        ];
        
        // Load SMS Configuration
        $smsResult = mysqli_query($this->conn, "SELECT * FROM notification_config WHERE type = 'sms'");
        if ($smsResult && mysqli_num_rows($smsResult) > 0) {
            $smsData = mysqli_fetch_assoc($smsResult);
            $smsConfigData = json_decode($smsData['config_data'], true) ?: [];
            $this->smsConfig = array_merge($defaultSmsConfig, $smsConfigData);
        } else {
            $this->smsConfig = $defaultSmsConfig;
        }
        
        // Load Email Configuration
        $emailResult = mysqli_query($this->conn, "SELECT * FROM notification_config WHERE type = 'email'");
        if ($emailResult && mysqli_num_rows($emailResult) > 0) {
            $emailData = mysqli_fetch_assoc($emailResult);
            $emailConfigData = json_decode($emailData['config_data'], true) ?: [];
            $this->emailConfig = array_merge($defaultEmailConfig, $emailConfigData);
        } else {
            $this->emailConfig = $defaultEmailConfig;
        }
    }
    
    /**
     * Send notification (SMS and/or Email)
     */
    public function sendNotification($userId, $type, $data = []) {
        $results = [
            'sms' => false,
            'email' => false,
            'errors' => []
        ];
        
        // Get user information
        $user = $this->getUserInfo($userId);
        if (!$user) {
            $results['errors'][] = 'User not found';
            return $results;
        }
        
        // Get notification template
        $template = $this->getNotificationTemplate($type);
        if (!$template) {
            $results['errors'][] = 'Notification template not found';
            return $results;
        }
        
        // Process template with data
        $processedTemplate = $this->processTemplate($template, $data, $user);
        
        // Send SMS if enabled and user has phone number
        if (isset($this->smsConfig['enabled']) && $this->smsConfig['enabled'] && !empty($user['phone'])) {
            $results['sms'] = $this->sendSMS($user['phone'], $processedTemplate['sms']);
            if (!$results['sms']) {
                $results['errors'][] = 'SMS sending failed';
            }
        } else if (isset($this->smsConfig['enabled']) && $this->smsConfig['enabled'] && empty($user['phone'])) {
            $results['errors'][] = 'SMS enabled but user has no phone number';
        }
        
        // Send Email if enabled and user has email
        if (isset($this->emailConfig['enabled']) && $this->emailConfig['enabled'] && !empty($user['email'])) {
            $results['email'] = $this->sendEmail($user['email'], $processedTemplate['email']['subject'], $processedTemplate['email']['body']);
            if (!$results['email']) {
                $results['errors'][] = 'Email sending failed';
            }
        }
        
        // Log notification attempt
        $this->logNotification($userId, $type, $results, $data);
        
        return $results;
    }
    
    /**
     * Send SMS notification
     */
    private function sendSMS($phoneNumber, $message) {
        if (!isset($this->smsConfig['enabled']) || !$this->smsConfig['enabled']) {
            return false;
        }
        
        // Clean phone number
        $phoneNumber = $this->cleanPhoneNumber($phoneNumber);
        if (!$phoneNumber) {
            return false;
        }
        
        // Use different SMS providers based on configuration
        $provider = $this->smsConfig['provider'] ?? 'generic';
        
        switch ($provider) {
            case 'smsonlinegh':
                return $this->sendSMSViaSMSOnlineGH($phoneNumber, $message);
            case 'generic':
            default:
                return $this->sendSMSViaGeneric($phoneNumber, $message);
        }
    }
    
    /**
     * Send SMS via Generic API
     */
    private function sendSMSViaGeneric($phoneNumber, $message) {
        $url = $this->smsConfig['api_url'];
        $apiKey = $this->smsConfig['api_key'];
        $senderId = $this->smsConfig['sender_id'];
        
        if (empty($url) || empty($apiKey)) {
            return false;
        }
        
        $data = [
            'to' => $phoneNumber,
            'message' => $message,
            'sender_id' => $senderId,
            'api_key' => $apiKey
        ];
        
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
        curl_setopt($ch, CURLOPT_HTTPHEADER, [
            'Content-Type: application/json',
            'Accept: application/json'
        ]);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_TIMEOUT, 30);
        
        $response = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);
        
        return $httpCode >= 200 && $httpCode < 300;
    }
    
    
    /**
     * Send SMS via SMS Online Ghana
     */
    private function sendSMSViaSMSOnlineGH($phoneNumber, $message) {
        $apiKey = $this->smsConfig['api_key'];
        $senderId = $this->smsConfig['sender_id'];
        
        if (empty($apiKey) || empty($senderId)) {
            error_log("SMS Online Ghana: Missing API key or sender ID");
            return false;
        }
        
        // Prepare phone number (ensure it starts with country code)
        if (strpos($phoneNumber, '233') !== 0) {
            if (strpos($phoneNumber, '0') === 0) {
                $phoneNumber = '233' . substr($phoneNumber, 1);
            } else {
                $phoneNumber = '233' . $phoneNumber;
            }
        }
        
        // Set up the request headers according to SMS Online Ghana API documentation
        $headers = [
            'Host: api.smsonlinegh.com',
            'Content-Type: application/json',
            'Accept: application/json',
            'Authorization: key ' . $apiKey
        ];
        
        // Set up the message data according to SMS Online Ghana API documentation
        $messageData = [
            'text' => $message,
            'type' => 0, // GSM default
            'sender' => $senderId,
            'destinations' => [$phoneNumber]
        ];
        
        // Optional: Set delivery callback information (can be configured later)
        // $messageData['callback']['url'] = 'https://yourdomain.com/sms_callback';
        // $messageData['callback']['accept'] = 'application/json';
        
        // Initialize cURL with the correct endpoint
        $ch = curl_init('https://api.smsonlinegh.com/v5/sms/send');
        
        // Set cURL options according to SMS Online Ghana API documentation
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($messageData));
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_TIMEOUT, 30);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // Disable SSL verification for local development
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); // Disable SSL host verification for local development
        
        // Execute for response
        $response = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $error = curl_error($ch);
        
        // Close curl
        curl_close($ch);
        
        // Log the attempt
        error_log("SMS Online Ghana - HTTP Code: $httpCode, Response: $response, Error: $error");
        
        // Check if successful (SMS Online Ghana returns 200 for success)
        if ($httpCode == 200) {
            error_log("SMS Online Ghana: Success - Response: $response");
            return true;
        } else {
            error_log("SMS Online Ghana: Failed - HTTP Code: $httpCode, Response: $response");
            return false;
        }
    }
    
    /**
     * Send Email notification
     */
    public function sendEmail($email, $subject, $body) {
        if (!isset($this->emailConfig['enabled']) || !$this->emailConfig['enabled']) {
            return false;
        }
        
        // Check if required SMTP settings are available
        if (empty($this->emailConfig['smtp_host']) || empty($this->emailConfig['smtp_username']) || empty($this->emailConfig['smtp_password'])) {
            error_log("Email configuration incomplete: missing SMTP settings");
            return false;
        }
        
        // Use PHPMailer if available, otherwise use custom SMTP implementation
        if (class_exists('PHPMailer\PHPMailer\PHPMailer')) {
            return $this->sendEmailViaPHPMailer($email, $subject, $body);
        } else {
            return $this->sendEmailViaCustomSMTP($email, $subject, $body);
        }
    }
    
    /**
     * Send Email via PHPMailer
     */
    private function sendEmailViaPHPMailer($email, $subject, $body) {
        try {
            $mail = new PHPMailer\PHPMailer\PHPMailer(true);
            
            // Server settings
            $mail->isSMTP();
            $mail->Host = $this->emailConfig['smtp_host'];
            $mail->SMTPAuth = true;
            $mail->Username = $this->emailConfig['smtp_username'];
            $mail->Password = $this->emailConfig['smtp_password'];
            $mail->Port = $this->emailConfig['smtp_port'];
            
            // Set encryption based on port
            if ($this->emailConfig['smtp_port'] == 465) {
                $mail->SMTPSecure = PHPMailer\PHPMailer\PHPMailer::ENCRYPTION_SMTPS;
            } else {
                $mail->SMTPSecure = PHPMailer\PHPMailer\PHPMailer::ENCRYPTION_STARTTLS;
            }
            
            // Additional settings for better compatibility
            $mail->SMTPOptions = array(
                'ssl' => array(
                    'verify_peer' => false,
                    'verify_peer_name' => false,
                    'allow_self_signed' => true
                )
            );
            
            // Recipients
            $mail->setFrom($this->emailConfig['from_email'], $this->emailConfig['from_name']);
            $mail->addAddress($email);
            
            // Content
            $mail->isHTML(true);
            $mail->Subject = $subject;
            $mail->Body = $body;
            
            $mail->send();
            return true;
        } catch (Exception $e) {
            error_log("Email sending failed: " . $e->getMessage());
            return false;
        }
    }
    
    /**
     * Send Email via custom SMTP implementation
     */
    private function sendEmailViaCustomSMTP($email, $subject, $body) {
        try {
            $host = $this->emailConfig['smtp_host'];
            $port = $this->emailConfig['smtp_port'];
            $username = $this->emailConfig['smtp_username'];
            $password = $this->emailConfig['smtp_password'];
            $fromEmail = $this->emailConfig['from_email'];
            $fromName = $this->emailConfig['from_name'];
            
            // Use stream_socket_client for better error handling
            $context = stream_context_create();
            
            // Use SSL for port 465, TCP for port 587
            if ($port == 465) {
                $socket = stream_socket_client("ssl://$host:$port", $errno, $errstr, 30, STREAM_CLIENT_CONNECT, $context);
            } else {
                $socket = stream_socket_client("tcp://$host:$port", $errno, $errstr, 30, STREAM_CLIENT_CONNECT, $context);
            }
            
            if (!$socket) {
                error_log("SMTP connection failed: $errstr ($errno)");
                return false;
            }
            
            // Set timeout
            stream_set_timeout($socket, 30);
            
            // Read initial response
            $response = fgets($socket, 515);
            if (!$response || substr($response, 0, 3) != '220') {
                error_log("SMTP server error: " . ($response ?: "No response"));
                fclose($socket);
                return false;
            }
            
            // Send EHLO command and read all responses
            fwrite($socket, "EHLO " . (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : 'localhost') . "\r\n");
            
            // Read all EHLO responses (Gmail sends multiple lines)
            do {
                $response = fgets($socket, 515);
            } while ($response && substr($response, 3, 1) == '-');
            
            // Start TLS if port is 587 (not needed for port 465 as it's already SSL)
            if ($port == 587) {
                fwrite($socket, "STARTTLS\r\n");
                $response = fgets($socket, 515);
                if (!$response || substr($response, 0, 3) != '220') {
                    error_log("STARTTLS failed: " . ($response ?: "No response"));
                    fclose($socket);
                    return false;
                }
                
                // Enable crypto
                if (!stream_socket_enable_crypto($socket, true, STREAM_CRYPTO_METHOD_TLS_CLIENT)) {
                    error_log("TLS encryption failed");
                    fclose($socket);
                    return false;
                }
                
                // Send EHLO again after TLS and read all responses
                fwrite($socket, "EHLO " . (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : 'localhost') . "\r\n");
                do {
                    $response = fgets($socket, 515);
                } while ($response && substr($response, 3, 1) == '-');
            }
            
            // Authenticate
            fwrite($socket, "AUTH LOGIN\r\n");
            $response = fgets($socket, 515);
            if (!$response || substr($response, 0, 3) != '334') {
                error_log("AUTH LOGIN failed: " . ($response ?: "No response"));
                fclose($socket);
                return false;
            }
            
            fwrite($socket, base64_encode($username) . "\r\n");
            $response = fgets($socket, 515);
            if (!$response || substr($response, 0, 3) != '334') {
                error_log("Username authentication failed: " . ($response ?: "No response"));
                fclose($socket);
                return false;
            }
            
            fwrite($socket, base64_encode($password) . "\r\n");
            $response = fgets($socket, 515);
            if (!$response || substr($response, 0, 3) != '235') {
                error_log("Password authentication failed: " . ($response ?: "No response"));
                fclose($socket);
                return false;
            }
            
            // Send MAIL FROM
            fwrite($socket, "MAIL FROM: <$fromEmail>\r\n");
            $response = fgets($socket, 515);
            if (!$response || substr($response, 0, 3) != '250') {
                error_log("MAIL FROM failed: " . ($response ?: "No response"));
                fclose($socket);
                return false;
            }
            
            // Send RCPT TO
            fwrite($socket, "RCPT TO: <$email>\r\n");
            $response = fgets($socket, 515);
            if (!$response || substr($response, 0, 3) != '250') {
                error_log("RCPT TO failed: " . ($response ?: "No response"));
                fclose($socket);
                return false;
            }
            
            // Send DATA
            fwrite($socket, "DATA\r\n");
            $response = fgets($socket, 515);
            if (!$response || substr($response, 0, 3) != '354') {
                error_log("DATA command failed: " . ($response ?: "No response"));
                fclose($socket);
                return false;
            }
            
            // Send email headers and body
            $headers = "From: $fromName <$fromEmail>\r\n";
            $headers .= "To: $email\r\n";
            $headers .= "Subject: $subject\r\n";
            $headers .= "MIME-Version: 1.0\r\n";
            $headers .= "Content-Type: text/html; charset=UTF-8\r\n";
            $headers .= "X-Mailer: PHP/" . phpversion() . "\r\n";
            $headers .= "\r\n";
            
            fwrite($socket, $headers . $body . "\r\n.\r\n");
            $response = fgets($socket, 515);
            if (!$response || substr($response, 0, 3) != '250') {
                error_log("Email sending failed: " . ($response ?: "No response"));
                fclose($socket);
                return false;
            }
            
            // Send QUIT
            fwrite($socket, "QUIT\r\n");
            fclose($socket);
            
            return true;
            
        } catch (Exception $e) {
            error_log("SMTP error: " . $e->getMessage());
            if (isset($socket)) {
                fclose($socket);
            }
            return false;
        }
    }
    
    /**
     * Get user information
     */
    private function getUserInfo($userId) {
        $stmt = $this->conn->prepare("SELECT id, username, email, phone FROM agents WHERE id = ?");
        $stmt->bind_param("i", $userId);
        $stmt->execute();
        $result = $stmt->get_result();
        
        if ($result->num_rows > 0) {
            return $result->fetch_assoc();
        }
        
        return null;
    }
    
    /**
     * Get notification template
     */
    private function getNotificationTemplate($type) {
        $stmt = $this->conn->prepare("SELECT * FROM notification_templates WHERE type = ? AND is_active = 1");
        $stmt->bind_param("s", $type);
        $stmt->execute();
        $result = $stmt->get_result();
        
        if ($result->num_rows > 0) {
            return $result->fetch_assoc();
        }
        
        return null;
    }
    
    /**
     * Process template with data
     */
    private function processTemplate($template, $data, $user) {
        $processed = [
            'sms' => $template['sms_template'],
            'email' => [
                'subject' => $template['email_subject'],
                'body' => $template['email_template']
            ]
        ];
        
        // Replace placeholders
        $placeholders = [
            '{username}' => $user['username'],
            '{email}' => $user['email'],
            '{phone}' => $user['phone'],
            '{amount}' => $data['amount'] ?? '',
            '{balance}' => $data['balance'] ?? '',
            '{date}' => $data['date'] ?? date('Y-m-d H:i:s'),
            '{login_time}' => $data['login_time'] ?? date('Y-m-d H:i:s'),
            '{ip_address}' => $data['ip_address'] ?? 'Unknown',
            '{user_agent}' => $data['user_agent'] ?? 'Unknown',
            '{device}' => $data['device'] ?? 'Unknown',
            '{browser}' => $data['browser'] ?? 'Unknown',
            '{location}' => $data['location'] ?? 'Unknown',
            '{site_name}' => 'D-Bundles Stores'
        ];
        
        foreach ($placeholders as $placeholder => $value) {
            $processed['sms'] = str_replace($placeholder, $value, $processed['sms']);
            $processed['email']['subject'] = str_replace($placeholder, $value, $processed['email']['subject']);
            $processed['email']['body'] = str_replace($placeholder, $value, $processed['email']['body']);
        }
        
        return $processed;
    }
    
    /**
     * Clean phone number
     */
    private function cleanPhoneNumber($phone) {
        // Remove all non-digit characters
        $phone = preg_replace('/\D/', '', $phone);
        
        // Handle Ghana phone numbers
        if (strlen($phone) == 10 && substr($phone, 0, 1) == '0') {
            $phone = '233' . substr($phone, 1);
        } elseif (strlen($phone) == 9) {
            $phone = '233' . $phone;
        }
        
        return $phone;
    }
    
    /**
     * Log notification attempt
     */
    private function logNotification($userId, $type, $results, $data) {
        $stmt = $this->conn->prepare("
            INSERT INTO notification_logs (user_id, notification_type, sms_sent, email_sent, errors, data, created_at)
            VALUES (?, ?, ?, ?, ?, ?, NOW())
        ");
        
        $smsSent = $results['sms'] ? 1 : 0;
        $emailSent = $results['email'] ? 1 : 0;
        $errors = json_encode($results['errors']);
        $dataJson = json_encode($data);
        
        $stmt->bind_param("isiiis", $userId, $type, $smsSent, $emailSent, $errors, $dataJson);
        $stmt->execute();
        $stmt->close();
    }
    
    /**
     * Update configuration
     */
    public function updateConfiguration($type, $config) {
        $stmt = $this->conn->prepare("
            INSERT INTO notification_config (type, config_data, updated_at)
            VALUES (?, ?, NOW())
            ON DUPLICATE KEY UPDATE config_data = VALUES(config_data), updated_at = NOW()
        ");
        
        $configJson = json_encode($config);
        $stmt->bind_param("ss", $type, $configJson);
        $result = $stmt->execute();
        $stmt->close();
        
        // Reload configurations
        $this->loadConfigurations();
        
        return $result;
    }
    
    /**
     * Get notification logs
     */
    public function getNotificationLogs($limit = 100, $offset = 0) {
        $stmt = $this->conn->prepare("
            SELECT nl.*, a.username, a.email
            FROM notification_logs nl
            LEFT JOIN agents a ON nl.user_id = a.id
            ORDER BY nl.created_at DESC
            LIMIT ? OFFSET ?
        ");
        $stmt->bind_param("ii", $limit, $offset);
        $stmt->execute();
        $result = $stmt->get_result();
        
        $logs = [];
        while ($row = $result->fetch_assoc()) {
            $logs[] = $row;
        }
        
        $stmt->close();
        return $logs;
    }
    
    /**
     * Test SMS configuration
     */
    public function testSMS($phoneNumber, $message = 'Test SMS from D-Bundles Stores') {
        return $this->sendSMS($phoneNumber, $message);
    }
    
    /**
     * Test Email configuration
     */
    public function testEmail($email, $subject = 'Test Email from D-Bundles Stores', $message = 'This is a test email from D-Bundles Stores notification system.') {
        return $this->sendEmail($email, $subject, $message);
    }
    
    /**
     * Get SMS configuration
     */
    public function getSMSConfig() {
        return $this->smsConfig;
    }
    
    /**
     * Get Email configuration
     */
    public function getEmailConfig() {
        return $this->emailConfig;
    }
    
    /**
     * Get notification template (public method for testing)
     */
    public function getNotificationTemplatePublic($type) {
        return $this->getNotificationTemplate($type);
    }
}
?>
