/**
 * Descomplicar® Crescimento Digital
 * https://descomplicar.pt
 */

<?php

defined('BASEPATH') or exit('No direct script access allowed');

/**
 * Client Notification Service
 * Handles notifications for client portal users
 * 
 * @package    Desk-Moloni
 * @version    3.0.0
 * @author     Descomplicar Business Solutions
 */
class ClientNotificationService
{
    private $CI;
    private $notificationsTable = 'desk_moloni_client_notifications';

    public function __construct()
    {
        $this->CI =& get_instance();
        $this->CI->load->database();
        $this->CI->load->helper('date');
        
        // Create notifications table if it doesn't exist
        $this->_ensureNotificationsTableExists();
    }

    /**
     * Create a new notification for a client
     * 
     * @param int $clientId Client ID
     * @param string $type Notification type
     * @param string $title Notification title
     * @param string $message Notification message
     * @param int|null $documentId Related document ID (optional)
     * @param string|null $actionUrl Action URL (optional)
     * @return int|false Notification ID or false on failure
     */
    public function createNotification($clientId, $type, $title, $message, $documentId = null, $actionUrl = null)
    {
        try {
            $data = [
                'client_id' => (int) $clientId,
                'type' => $type,
                'title' => $title,
                'message' => $message,
                'document_id' => $documentId ? (int) $documentId : null,
                'action_url' => $actionUrl,
                'is_read' => 0,
                'created_at' => date('Y-m-d H:i:s')
            ];

            // Validate notification type
            if (!$this->_isValidNotificationType($type)) {
                throw new Exception('Invalid notification type: ' . $type);
            }

            // Validate client exists
            if (!$this->_clientExists($clientId)) {
                throw new Exception('Client does not exist: ' . $clientId);
            }

            $result = $this->CI->db->insert($this->notificationsTable, $data);
            
            if ($result) {
                $notificationId = $this->CI->db->insert_id();
                
                // Log notification creation
                log_message('info', "Notification created: ID {$notificationId} for client {$clientId}");
                
                return $notificationId;
            }

            return false;

        } catch (Exception $e) {
            log_message('error', 'Create notification error: ' . $e->getMessage());
            return false;
        }
    }

    /**
     * Get notifications for a client
     * 
     * @param int $clientId Client ID
     * @param bool $unreadOnly Get only unread notifications
     * @param int $limit Maximum number of notifications
     * @param int $offset Offset for pagination
     * @return array Notifications
     */
    public function getClientNotifications($clientId, $unreadOnly = false, $limit = 20, $offset = 0)
    {
        try {
            $this->CI->db->where('client_id', $clientId);
            
            if ($unreadOnly) {
                $this->CI->db->where('is_read', 0);
            }
            
            $query = $this->CI->db->order_by('created_at', 'DESC')
                                 ->limit($limit, $offset)
                                 ->get($this->notificationsTable);
            
            $notifications = $query->result_array();
            
            // Format notifications
            foreach ($notifications as &$notification) {
                $notification['id'] = (int) $notification['id'];
                $notification['client_id'] = (int) $notification['client_id'];
                $notification['document_id'] = $notification['document_id'] ? (int) $notification['document_id'] : null;
                $notification['is_read'] = (bool) $notification['is_read'];
            }
            
            return $notifications;

        } catch (Exception $e) {
            log_message('error', 'Get client notifications error: ' . $e->getMessage());
            return [];
        }
    }

    /**
     * Get unread notifications count for a client
     * 
     * @param int $clientId Client ID
     * @return int Unread count
     */
    public function getUnreadCount($clientId)
    {
        try {
            return $this->CI->db->where('client_id', $clientId)
                               ->where('is_read', 0)
                               ->count_all_results($this->notificationsTable);

        } catch (Exception $e) {
            log_message('error', 'Get unread count error: ' . $e->getMessage());
            return 0;
        }
    }

    /**
     * Mark notification as read
     * 
     * @param int $notificationId Notification ID
     * @param int $clientId Client ID (for security check)
     * @return bool Success status
     */
    public function markAsRead($notificationId, $clientId)
    {
        try {
            $this->CI->db->where('id', $notificationId)
                         ->where('client_id', $clientId);
            
            $result = $this->CI->db->update($this->notificationsTable, [
                'is_read' => 1,
                'read_at' => date('Y-m-d H:i:s')
            ]);

            return $result && $this->CI->db->affected_rows() > 0;

        } catch (Exception $e) {
            log_message('error', 'Mark notification as read error: ' . $e->getMessage());
            return false;
        }
    }

    /**
     * Mark all notifications as read for a client
     * 
     * @param int $clientId Client ID
     * @return bool Success status
     */
    public function markAllAsRead($clientId)
    {
        try {
            $this->CI->db->where('client_id', $clientId)
                         ->where('is_read', 0);
            
            $result = $this->CI->db->update($this->notificationsTable, [
                'is_read' => 1,
                'read_at' => date('Y-m-d H:i:s')
            ]);

            return $result;

        } catch (Exception $e) {
            log_message('error', 'Mark all notifications as read error: ' . $e->getMessage());
            return false;
        }
    }

    /**
     * Delete old notifications
     * 
     * @param int $olderThanDays Delete notifications older than X days
     * @return int Number of deleted notifications
     */
    public function cleanupOldNotifications($olderThanDays = 90)
    {
        try {
            $cutoffDate = date('Y-m-d H:i:s', strtotime("-{$olderThanDays} days"));
            
            $this->CI->db->where('created_at <', $cutoffDate);
            $result = $this->CI->db->delete($this->notificationsTable);
            
            return $this->CI->db->affected_rows();

        } catch (Exception $e) {
            log_message('error', 'Cleanup old notifications error: ' . $e->getMessage());
            return 0;
        }
    }

    /**
     * Create document notification when a new document is available
     * 
     * @param int $clientId Client ID
     * @param int $documentId Document ID
     * @param string $documentType Document type (invoice, estimate, etc.)
     * @param string $documentNumber Document number
     * @return int|false Notification ID or false on failure
     */
    public function notifyDocumentCreated($clientId, $documentId, $documentType, $documentNumber)
    {
        $title = 'New ' . ucfirst($documentType) . ' Available';
        $message = "A new {$documentType} ({$documentNumber}) is now available for viewing.";
        $actionUrl = site_url("clients/desk_moloni/documents/{$documentId}");

        return $this->createNotification(
            $clientId,
            'document_created',
            $title,
            $message,
            $documentId,
            $actionUrl
        );
    }

    /**
     * Create payment received notification
     * 
     * @param int $clientId Client ID
     * @param int $documentId Document ID
     * @param float $amount Payment amount
     * @param string $documentNumber Document number
     * @return int|false Notification ID or false on failure
     */
    public function notifyPaymentReceived($clientId, $documentId, $amount, $documentNumber)
    {
        $title = 'Payment Received';
        $message = "Payment of " . number_format($amount, 2) . " received for {$documentNumber}.";
        $actionUrl = site_url("clients/desk_moloni/documents/{$documentId}");

        return $this->createNotification(
            $clientId,
            'payment_received',
            $title,
            $message,
            $documentId,
            $actionUrl
        );
    }

    /**
     * Create overdue notice notification
     * 
     * @param int $clientId Client ID
     * @param int $documentId Document ID
     * @param string $documentNumber Document number
     * @param string $dueDate Due date
     * @return int|false Notification ID or false on failure
     */
    public function notifyOverdue($clientId, $documentId, $documentNumber, $dueDate)
    {
        $title = 'Payment Overdue';
        $message = "Payment for {$documentNumber} was due on {$dueDate}. Please review your account.";
        $actionUrl = site_url("clients/desk_moloni/documents/{$documentId}");

        return $this->createNotification(
            $clientId,
            'overdue_notice',
            $title,
            $message,
            $documentId,
            $actionUrl
        );
    }

    /**
     * Create system message notification
     * 
     * @param int $clientId Client ID
     * @param string $title Message title
     * @param string $message Message content
     * @return int|false Notification ID or false on failure
     */
    public function notifySystemMessage($clientId, $title, $message)
    {
        return $this->createNotification(
            $clientId,
            'system_message',
            $title,
            $message
        );
    }

    /**
     * Get notification by ID
     * 
     * @param int $notificationId Notification ID
     * @param int $clientId Client ID (for security check)
     * @return array|null Notification data or null if not found
     */
    public function getNotificationById($notificationId, $clientId)
    {
        try {
            $query = $this->CI->db->where('id', $notificationId)
                               ->where('client_id', $clientId)
                               ->get($this->notificationsTable);

            $notification = $query->row_array();
            
            if ($notification) {
                $notification['id'] = (int) $notification['id'];
                $notification['client_id'] = (int) $notification['client_id'];
                $notification['document_id'] = $notification['document_id'] ? (int) $notification['document_id'] : null;
                $notification['is_read'] = (bool) $notification['is_read'];
            }
            
            return $notification;

        } catch (Exception $e) {
            log_message('error', 'Get notification by ID error: ' . $e->getMessage());
            return null;
        }
    }

    // Private Methods

    /**
     * Ensure notifications table exists
     */
    private function _ensureNotificationsTableExists()
    {
        if (!$this->CI->db->table_exists($this->notificationsTable)) {
            $this->_createNotificationsTable();
        }
    }

    /**
     * Create notifications table
     */
    private function _createNotificationsTable()
    {
        $sql = "
            CREATE TABLE IF NOT EXISTS `{$this->notificationsTable}` (
                `id` int(11) NOT NULL AUTO_INCREMENT,
                `client_id` int(11) NOT NULL,
                `type` enum('document_created','payment_received','overdue_notice','system_message') NOT NULL,
                `title` varchar(255) NOT NULL,
                `message` text NOT NULL,
                `document_id` int(11) DEFAULT NULL,
                `action_url` varchar(500) DEFAULT NULL,
                `is_read` tinyint(1) NOT NULL DEFAULT 0,
                `created_at` datetime NOT NULL,
                `read_at` datetime DEFAULT NULL,
                PRIMARY KEY (`id`),
                KEY `idx_client_id` (`client_id`),
                KEY `idx_client_unread` (`client_id`, `is_read`),
                KEY `idx_created_at` (`created_at`),
                KEY `idx_document_id` (`document_id`)
            ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
        ";

        $this->CI->db->query($sql);
        
        if ($this->CI->db->error()['code'] !== 0) {
            log_message('error', 'Failed to create notifications table: ' . $this->CI->db->error()['message']);
        } else {
            log_message('info', 'Notifications table created successfully');
        }
    }

    /**
     * Check if notification type is valid
     */
    private function _isValidNotificationType($type)
    {
        $validTypes = [
            'document_created',
            'payment_received',
            'overdue_notice',
            'system_message'
        ];

        return in_array($type, $validTypes);
    }

    /**
     * Check if client exists
     */
    private function _clientExists($clientId)
    {
        $count = $this->CI->db->where('userid', $clientId)
                             ->count_all_results('tblclients');
        return $count > 0;
    }
}