<?php
/**
 * ============================================================================
 * classes/Message.php - Message Management Class with E2E Encryption
 * ============================================================================
 */

namespace App;

class Message {
    private $conn;
    private $table_name = "messages";
    
    public function __construct($db) {
        $this->conn = $db;
    }
    
    /**
     * Get chat messages with proper encryption handling
     */
    public function getChatMessages($chatId, $userId, $limit = 50, $beforeId = null) {
        $query = "SELECT 
                    m.id,
                    m.chat_id,
                    m.sender_id,
                    m.message_type,
                    m.content,
                    m.is_encrypted,
                    m.encrypted_content,
                    m.media_url,
                    m.created_at,
                    m.updated_at,
                    u.full_name as sender_name,
                    u.profile_picture as sender_avatar
                FROM {$this->table_name} m
                INNER JOIN users u ON m.sender_id = u.id
                WHERE m.chat_id = :chat_id";
        
        if ($beforeId) {
            $query .= " AND m.id < :before_id";
        }
        
        $query .= " ORDER BY m.created_at DESC LIMIT :limit";
        
        $stmt = $this->conn->prepare($query);
        $stmt->bindParam(':chat_id', $chatId, \PDO::PARAM_INT);
        $stmt->bindParam(':limit', $limit, \PDO::PARAM_INT);
        
        if ($beforeId) {
            $stmt->bindParam(':before_id', $beforeId, \PDO::PARAM_INT);
        }
        
        $stmt->execute();
        $messages = $stmt->fetchAll(\PDO::FETCH_ASSOC);
        
        // Reverse to show oldest first
        return array_reverse($messages);
    }
    
    /**
     * Send a message with optional encryption
     */
    public function send($chatId, $senderId, $data, $encrypt = false) {
        try {
            $content = $data['content'] ?? '';
            $messageType = $data['message_type'] ?? 'text';
            $mediaUrl = $data['media_url'] ?? null;
            
            // If encryption is enabled, get recipient's public key
            $encryptedContent = null;
            $encryptedKey = null;
            $iv = null;
            $messageHash = null;
            $senderSignature = null;
            
            if ($encrypt) {
                // Get the other user in the chat
                $recipientQuery = "SELECT user_id 
                                  FROM chat_members 
                                  WHERE chat_id = :chat_id 
                                  AND user_id != :sender_id 
                                  LIMIT 1";
                
                $stmt = $this->conn->prepare($recipientQuery);
                $stmt->bindParam(':chat_id', $chatId);
                $stmt->bindParam(':sender_id', $senderId);
                $stmt->execute();
                
                $recipient = $stmt->fetch(\PDO::FETCH_ASSOC);
                
                if (!$recipient) {
                    return [
                        'success' => false,
                        'message' => 'Recipient not found'
                    ];
                }
                
                // Get recipient's public key
                $keyQuery = "SELECT public_key FROM user_encryption_keys WHERE user_id = :user_id";
                $stmt = $this->conn->prepare($keyQuery);
                $stmt->bindParam(':user_id', $recipient['user_id']);
                $stmt->execute();
                
                $keyData = $stmt->fetch(\PDO::FETCH_ASSOC);
                
                if (!$keyData) {
                    return [
                        'success' => false,
                        'message' => 'Recipient encryption keys not found'
                    ];
                }
                
                // Encrypt the message
                $encryption = new Encryption();
                $encryptedData = $encryption->encryptMessage($content, $keyData['public_key']);
                
                if (!$encryptedData) {
                    return [
                        'success' => false,
                        'message' => 'Failed to encrypt message'
                    ];
                }
                
                $encryptedContent = $encryptedData['encrypted_message'];
                $encryptedKey = $encryptedData['encrypted_key'];
                $iv = $encryptedData['iv'];
                $messageHash = hash('sha256', $content);
                
                // Get sender's private key for signature (in production, this comes from client)
                // For now, we'll skip signature or implement it differently
            }
            
            // Insert message
            $query = "INSERT INTO {$this->table_name} 
                     (chat_id, sender_id, message_type, content, encrypted_content, 
                      encrypted_key, iv, message_hash, media_url, is_encrypted, created_at)
                     VALUES 
                     (:chat_id, :sender_id, :message_type, :content, :encrypted_content,
                      :encrypted_key, :iv, :message_hash, :media_url, :is_encrypted, NOW())";
            
            $stmt = $this->conn->prepare($query);
            $stmt->bindParam(':chat_id', $chatId);
            $stmt->bindParam(':sender_id', $senderId);
            $stmt->bindParam(':message_type', $messageType);
            $stmt->bindParam(':content', $content);
            $stmt->bindParam(':encrypted_content', $encryptedContent);
            $stmt->bindParam(':encrypted_key', $encryptedKey);
            $stmt->bindParam(':iv', $iv);
            $stmt->bindParam(':message_hash', $messageHash);
            $stmt->bindParam(':media_url', $mediaUrl);
            $isEncrypted = $encrypt ? 1 : 0;
            $stmt->bindParam(':is_encrypted', $isEncrypted);
            
            if ($stmt->execute()) {
                $messageId = $this->conn->lastInsertId();
                
                // Create notification for recipient (if not encrypted or handle differently)
                $this->notifyRecipient($chatId, $senderId, $messageId);
                
                return [
                    'success' => true,
                    'message_id' => $messageId,
                    'is_encrypted' => $encrypt
                ];
            }
            
            return [
                'success' => false,
                'message' => 'Failed to send message'
            ];
            
        } catch (\Exception $e) {
            error_log('Send message error: ' . $e->getMessage());
            return [
                'success' => false,
                'message' => 'Error sending message: ' . $e->getMessage()
            ];
        }
    }
    
    /**
     * Get new messages after a specific message ID
     */
    public function getNewMessages($chatId, $userId, $afterId) {
        $query = "SELECT 
                    m.id,
                    m.chat_id,
                    m.sender_id,
                    m.message_type,
                    m.content,
                    m.is_encrypted,
                    m.encrypted_content,
                    m.media_url,
                    m.created_at,
                    u.full_name as sender_name,
                    u.profile_picture as sender_avatar
                FROM {$this->table_name} m
                INNER JOIN users u ON m.sender_id = u.id
                WHERE m.chat_id = :chat_id 
                AND m.id > :after_id
                ORDER BY m.created_at ASC";
        
        $stmt = $this->conn->prepare($query);
        $stmt->bindParam(':chat_id', $chatId);
        $stmt->bindParam(':after_id', $afterId);
        $stmt->execute();
        
        return $stmt->fetchAll(\PDO::FETCH_ASSOC);
    }
    
    /**
     * Decrypt an encrypted message
     */
    public function decryptMessage($messageId, $userId, $privateKey) {
        try {
            // Get the encrypted message
            $query = "SELECT 
                        m.encrypted_content,
                        m.encrypted_key,
                        m.iv,
                        m.message_hash,
                        m.sender_id
                     FROM {$this->table_name} m
                     WHERE m.id = :message_id 
                     AND m.is_encrypted = 1";
            
            $stmt = $this->conn->prepare($query);
            $stmt->bindParam(':message_id', $messageId);
            $stmt->execute();
            
            $message = $stmt->fetch(\PDO::FETCH_ASSOC);
            
            if (!$message) {
                return [
                    'success' => false,
                    'message' => 'Message not found or not encrypted'
                ];
            }
            
            // Decrypt the message
            $encryption = new Encryption();
            $decrypted = $encryption->decryptMessage([
                'encrypted_message' => $message['encrypted_content'],
                'encrypted_key' => $message['encrypted_key'],
                'iv' => $message['iv']
            ], $privateKey);
            
            if ($decrypted === false) {
                return [
                    'success' => false,
                    'message' => 'Failed to decrypt message'
                ];
            }
            
            // Verify message integrity
            $verified = hash('sha256', $decrypted) === $message['message_hash'];
            
            return [
                'success' => true,
                'decrypted_message' => $decrypted,
                'verified' => $verified
            ];
            
        } catch (\Exception $e) {
            error_log('Decrypt message error: ' . $e->getMessage());
            return [
                'success' => false,
                'message' => 'Error decrypting message: ' . $e->getMessage()
            ];
        }
    }
    
    /**
     * Get unread message count for a user
     */
    public function getUnreadCount($userId) {
        $query = "SELECT COUNT(DISTINCT m.id) as unread_count
                 FROM {$this->table_name} m
                 INNER JOIN chat_members cm ON m.chat_id = cm.chat_id
                 WHERE cm.user_id = :user_id
                 AND m.sender_id != :user_id2
                 AND m.created_at > COALESCE(cm.last_read_at, '2000-01-01')";
        
        $stmt = $this->conn->prepare($query);
        $stmt->bindParam(':user_id', $userId);
        $stmt->bindParam(':user_id2', $userId);
        $stmt->execute();
        
        $result = $stmt->fetch(\PDO::FETCH_ASSOC);
        return $result['unread_count'] ?? 0;
    }
    
    /**
     * Notify recipient of new message
     */
    private function notifyRecipient($chatId, $senderId, $messageId) {
        // Get recipient
        $query = "SELECT user_id FROM chat_members 
                 WHERE chat_id = :chat_id AND user_id != :sender_id";
        
        $stmt = $this->conn->prepare($query);
        $stmt->bindParam(':chat_id', $chatId);
        $stmt->bindParam(':sender_id', $senderId);
        $stmt->execute();
        
        $recipient = $stmt->fetch(\PDO::FETCH_ASSOC);
        
        if ($recipient) {
            // Get sender name
            $senderQuery = "SELECT full_name FROM users WHERE id = :sender_id";
            $stmt = $this->conn->prepare($senderQuery);
            $stmt->bindParam(':sender_id', $senderId);
            $stmt->execute();
            $sender = $stmt->fetch(\PDO::FETCH_ASSOC);
            
            // Create notification
            $notifQuery = "INSERT INTO notifications 
                          (user_id, title, message, type, icon, link, created_at)
                          VALUES 
                          (:user_id, :title, :message, 'info', 'chat', :link, NOW())";
            
            $stmt = $this->conn->prepare($notifQuery);
            $stmt->bindParam(':user_id', $recipient['user_id']);
            $title = 'New Message';
            $stmt->bindParam(':title', $title);
            $messageText = ($sender['full_name'] ?? 'Someone') . ' sent you a message';
            $stmt->bindParam(':message', $messageText);
            $link = '/chat/one-on-one.php?chat_id=' . $chatId;
            $stmt->bindParam(':link', $link);
            $stmt->execute();
        }
    }
    
    /**
     * Mark messages as read
     */
    public function markAsRead($chatId, $userId) {
        $query = "UPDATE chat_members 
                 SET last_read_at = NOW() 
                 WHERE chat_id = :chat_id AND user_id = :user_id";
        
        $stmt = $this->conn->prepare($query);
        $stmt->bindParam(':chat_id', $chatId);
        $stmt->bindParam(':user_id', $userId);
        
        return $stmt->execute();
    }
    
    /**
     * Delete a message
     */
    public function delete($messageId, $userId) {
        // Only allow deletion of own messages within 5 minutes
        $query = "DELETE FROM {$this->table_name} 
                 WHERE id = :message_id 
                 AND sender_id = :user_id 
                 AND created_at > DATE_SUB(NOW(), INTERVAL 5 MINUTE)";
        
        $stmt = $this->conn->prepare($query);
        $stmt->bindParam(':message_id', $messageId);
        $stmt->bindParam(':user_id', $userId);
        
        return $stmt->execute();
    }
}