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

<?php
/**
 * Desk-Moloni v3.0 BULLETPROOF - Perfex CRM Module
 * 
 * Complete bidirectional synchronization between Perfex CRM and Moloni ERP
 * 100% SELF-CONTAINED - NO MIGRATION DEPENDENCIES
 * 
 * @package     DeskMoloni
 * @author      Descomplicar.pt
 * @version     3.0.1
 * @link        https://descomplicar.pt
 * @requires    PHP 8.0+
 * @requires    Perfex CRM 3.0+
 */

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

/*
Module Name: Desk-Moloni Integration v3.0
Description: Complete bidirectional synchronization between Perfex CRM and Moloni ERP with OAuth 2.0, queue processing, and client portal. 100% MIGRATION INDEPENDENT.
Version: 3.0.1
Requires at least: 3.0.*
Requires PHP: 8.0
Author: Descomplicar.pt
Author URI: https://descomplicar.pt
*/

// PHP 8.0+ compatibility check
if (version_compare(PHP_VERSION, '8.0.0', '<')) {
    throw new Exception('Desk-Moloni v3.0 requires PHP 8.0 or higher. Current version: ' . PHP_VERSION);
}

// Define constants with existence checks for PHP 8.0+ compatibility
if (!defined('DESK_MOLONI_MODULE_NAME')) {
    define('DESK_MOLONI_MODULE_NAME', 'desk_moloni');
}
if (!defined('DESK_MOLONI_VERSION')) {
    define('DESK_MOLONI_VERSION', '3.0.1');
}
if (!defined('DESK_MOLONI_MODULE_VERSION')) {
    define('DESK_MOLONI_MODULE_VERSION', '3.0.1');
}
if (!defined('DESK_MOLONI_MODULE_PATH')) {
    define('DESK_MOLONI_MODULE_PATH', dirname(__FILE__));
}
if (!defined('DESK_MOLONI_MIN_PHP_VERSION')) {
    define('DESK_MOLONI_MIN_PHP_VERSION', '8.0.0');
}

// Load Composer autoloader with error handling
if (file_exists(DESK_MOLONI_MODULE_PATH . '/vendor/autoload.php')) {
    require_once DESK_MOLONI_MODULE_PATH . '/vendor/autoload.php';
}

// Load module configuration and autoloader
if (file_exists(DESK_MOLONI_MODULE_PATH . '/config/autoload.php')) {
    require_once DESK_MOLONI_MODULE_PATH . '/config/autoload.php';
}

/**
 * BULLETPROOF MODULE INITIALIZATION
 * This section ensures the module works independently of any migration system
 */

// Initialize module with bulletproof error handling
if (!function_exists('desk_moloni_bulletproof_init')) {
    function desk_moloni_bulletproof_init()
    {
        try {
            // Verify database tables exist and create if needed
            desk_moloni_ensure_tables_exist();
            
            // Initialize default configuration if needed
            desk_moloni_ensure_configuration_exists();
            
            // Setup permissions if needed
            desk_moloni_ensure_permissions_exist();
            
            return true;
        } catch (Throwable $e) {
            error_log("Desk-Moloni bulletproof init error: " . $e->getMessage());
            return false;
        }
    }
}

/**
 * Enhanced hook registration with existence checks for stability
 * Prevents fatal errors in case hooks system is not available
 */

// Initialize module on every load (bulletproof approach)
desk_moloni_bulletproof_init();

// Sync hooks with function_exists checks for PHP 8.0+ compatibility
if (function_exists('hooks')) {
    // Customer sync hooks
    hooks()->add_action('after_client_added', 'desk_moloni_sync_customer_added');
    hooks()->add_action('after_client_updated', 'desk_moloni_sync_customer_updated');
    
    // Invoice sync hooks
    hooks()->add_action('after_invoice_added', 'desk_moloni_sync_invoice_added');
    hooks()->add_action('after_invoice_updated', 'desk_moloni_sync_invoice_updated');
    
    // Estimate sync hooks
    hooks()->add_action('after_estimate_added', 'desk_moloni_sync_estimate_added');
    hooks()->add_action('after_estimate_updated', 'desk_moloni_sync_estimate_updated');
    
    // Item/Product sync hooks
    hooks()->add_action('after_item_added', 'desk_moloni_sync_item_added');
    hooks()->add_action('after_item_updated', 'desk_moloni_sync_item_updated');
    
    // Admin interface hooks
    hooks()->add_action('admin_init', 'desk_moloni_admin_init_hook');
    hooks()->add_action('admin_init', 'desk_moloni_init_admin_menu');
    
    // Client portal hooks
    hooks()->add_action('client_init', 'desk_moloni_client_init_hook');
}

/**
 * BULLETPROOF DATABASE TABLE MANAGEMENT
 * Ensures all required tables exist without depending on migration system
 */
if (!function_exists('desk_moloni_ensure_tables_exist')) {
    function desk_moloni_ensure_tables_exist()
    {
        try {
            $CI = &get_instance();
            $CI->load->database();
            
            // Define all required tables
            $tables = [
                'desk_moloni_sync_queue' => "CREATE TABLE IF NOT EXISTS `" . db_prefix() . "desk_moloni_sync_queue` (
                    `id` int(11) NOT NULL AUTO_INCREMENT,
                    `entity_type` varchar(50) NOT NULL,
                    `entity_id` int(11) NOT NULL,
                    `perfex_id` int(11) DEFAULT NULL,
                    `moloni_id` int(11) DEFAULT NULL,
                    `action` enum('create','update','delete','sync') NOT NULL DEFAULT 'sync',
                    `direction` enum('perfex_to_moloni','moloni_to_perfex','bidirectional') NOT NULL DEFAULT 'bidirectional',
                    `priority` enum('low','normal','high','critical') NOT NULL DEFAULT 'normal',
                    `status` enum('pending','processing','completed','failed','cancelled') NOT NULL DEFAULT 'pending',
                    `attempts` int(11) NOT NULL DEFAULT 0,
                    `max_attempts` int(11) NOT NULL DEFAULT 3,
                    `data` longtext DEFAULT NULL COMMENT 'JSON data for sync',
                    `error_message` text DEFAULT NULL,
                    `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
                    `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
                    `scheduled_at` timestamp NULL DEFAULT NULL,
                    `started_at` timestamp NULL DEFAULT NULL,
                    `completed_at` timestamp NULL DEFAULT NULL,
                    `created_by` int(11) DEFAULT NULL,
                    PRIMARY KEY (`id`),
                    KEY `idx_entity_type_id` (`entity_type`, `entity_id`),
                    KEY `idx_status_priority` (`status`, `priority`),
                    KEY `idx_scheduled_at` (`scheduled_at`),
                    KEY `idx_perfex_id` (`perfex_id`),
                    KEY `idx_moloni_id` (`moloni_id`),
                    KEY `idx_created_by` (`created_by`)
                ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;",
                
                'desk_moloni_sync_logs' => "CREATE TABLE IF NOT EXISTS `" . db_prefix() . "desk_moloni_sync_logs` (
                    `id` int(11) NOT NULL AUTO_INCREMENT,
                    `queue_id` int(11) DEFAULT NULL,
                    `entity_type` varchar(50) NOT NULL,
                    `entity_id` int(11) NOT NULL,
                    `action` varchar(50) NOT NULL,
                    `direction` varchar(50) NOT NULL,
                    `status` enum('started','success','error','warning') NOT NULL,
                    `message` text DEFAULT NULL,
                    `request_data` longtext DEFAULT NULL COMMENT 'JSON request data',
                    `response_data` longtext DEFAULT NULL COMMENT 'JSON response data',
                    `execution_time` decimal(10,4) DEFAULT NULL COMMENT 'Execution time in seconds',
                    `memory_usage` int(11) DEFAULT NULL COMMENT 'Memory usage in bytes',
                    `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
                    `created_by` int(11) DEFAULT NULL,
                    PRIMARY KEY (`id`),
                    KEY `idx_queue_id` (`queue_id`),
                    KEY `idx_entity_type_id` (`entity_type`, `entity_id`),
                    KEY `idx_status` (`status`),
                    KEY `idx_created_at` (`created_at`)
                ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;",
                
                'desk_moloni_entity_mappings' => "CREATE TABLE IF NOT EXISTS `" . db_prefix() . "desk_moloni_entity_mappings` (
                    `id` int(11) NOT NULL AUTO_INCREMENT,
                    `entity_type` varchar(50) NOT NULL,
                    `perfex_id` int(11) NOT NULL,
                    `moloni_id` int(11) NOT NULL,
                    `perfex_hash` varchar(64) DEFAULT NULL COMMENT 'Hash of Perfex entity data',
                    `moloni_hash` varchar(64) DEFAULT NULL COMMENT 'Hash of Moloni entity data',
                    `sync_status` enum('synced','pending','error','conflict') NOT NULL DEFAULT 'synced',
                    `last_sync_at` timestamp NULL DEFAULT NULL,
                    `last_perfex_update` timestamp NULL DEFAULT NULL,
                    `last_moloni_update` timestamp NULL DEFAULT NULL,
                    `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
                    `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
                    `metadata` longtext DEFAULT NULL COMMENT 'Additional mapping metadata JSON',
                    PRIMARY KEY (`id`),
                    UNIQUE KEY `uk_entity_perfex` (`entity_type`, `perfex_id`),
                    UNIQUE KEY `uk_entity_moloni` (`entity_type`, `moloni_id`),
                    KEY `idx_sync_status` (`sync_status`),
                    KEY `idx_last_sync` (`last_sync_at`)
                ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;",
                
                'desk_moloni_configuration' => "CREATE TABLE IF NOT EXISTS `" . db_prefix() . "desk_moloni_configuration` (
                    `id` int(11) NOT NULL AUTO_INCREMENT,
                    `config_key` varchar(100) NOT NULL,
                    `config_value` longtext DEFAULT NULL,
                    `config_type` enum('string','integer','boolean','json','encrypted') NOT NULL DEFAULT 'string',
                    `description` text DEFAULT NULL,
                    `category` varchar(50) DEFAULT NULL,
                    `is_system` tinyint(1) NOT NULL DEFAULT 0,
                    `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
                    `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
                    `updated_by` int(11) DEFAULT NULL,
                    PRIMARY KEY (`id`),
                    UNIQUE KEY `uk_config_key` (`config_key`),
                    KEY `idx_category` (`category`),
                    KEY `idx_is_system` (`is_system`)
                ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;",
                
                'desk_moloni_api_tokens' => "CREATE TABLE IF NOT EXISTS `" . db_prefix() . "desk_moloni_api_tokens` (
                    `id` int(11) NOT NULL AUTO_INCREMENT,
                    `token_type` enum('access_token','refresh_token','webhook_token') NOT NULL,
                    `token_value` text NOT NULL COMMENT 'Encrypted token value',
                    `expires_at` timestamp NULL DEFAULT NULL,
                    `company_id` int(11) DEFAULT NULL,
                    `scopes` longtext DEFAULT NULL COMMENT 'JSON scopes',
                    `metadata` longtext DEFAULT NULL COMMENT 'JSON metadata',
                    `active` tinyint(1) NOT NULL DEFAULT 1,
                    `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
                    `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
                    `last_used_at` timestamp NULL DEFAULT NULL,
                    PRIMARY KEY (`id`),
                    KEY `idx_token_type` (`token_type`),
                    KEY `idx_company_id` (`company_id`),
                    KEY `idx_active` (`active`),
                    KEY `idx_expires_at` (`expires_at`)
                ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;"
            ];
            
            // Create each table
            foreach ($tables as $table_name => $sql) {
                try {
                    $CI->db->query($sql);
                } catch (Exception $e) {
                    error_log("Error creating table {$table_name}: " . $e->getMessage());
                }
            }
            
            return true;
        } catch (Throwable $e) {
            error_log("Desk-Moloni table creation error: " . $e->getMessage());
            return false;
        }
    }
}

/**
 * BULLETPROOF CONFIGURATION MANAGEMENT
 */
if (!function_exists('desk_moloni_ensure_configuration_exists')) {
    function desk_moloni_ensure_configuration_exists()
    {
        try {
            // Core API Configuration (as module options for backward compatibility)
            $default_options = [
                'desk_moloni_api_base_url' => 'https://api.moloni.pt/v1/',
                'desk_moloni_oauth_base_url' => 'https://www.moloni.pt/v1/',
                'desk_moloni_api_timeout' => '30',
                'desk_moloni_max_retries' => '3',
                'desk_moloni_client_id' => '',
                'desk_moloni_client_secret' => '',
                'desk_moloni_access_token' => '',
                'desk_moloni_refresh_token' => '',
                'desk_moloni_token_expires_at' => '',
                'desk_moloni_company_id' => '',
                'desk_moloni_auto_sync_enabled' => '1',
                'desk_moloni_realtime_sync_enabled' => '0',
                'desk_moloni_sync_delay' => '300',
                'desk_moloni_batch_sync_enabled' => '1',
                'desk_moloni_sync_customers' => '1',
                'desk_moloni_sync_invoices' => '1',
                'desk_moloni_sync_estimates' => '1',
                'desk_moloni_sync_credit_notes' => '1',
                'desk_moloni_sync_receipts' => '0',
                'desk_moloni_sync_products' => '0',
                'desk_moloni_enable_monitoring' => '1',
                'desk_moloni_enable_performance_tracking' => '1',
                'desk_moloni_enable_caching' => '1',
                'desk_moloni_cache_ttl' => '3600',
                'desk_moloni_enable_encryption' => '1',
                'desk_moloni_webhook_signature_verification' => '1',
                'desk_moloni_enable_audit_logging' => '1',
                'desk_moloni_enable_logging' => '1',
                'desk_moloni_log_level' => 'info',
                'desk_moloni_log_api_requests' => '0',
                'desk_moloni_log_retention_days' => '30',
                'desk_moloni_enable_queue' => '1',
                'desk_moloni_queue_batch_size' => '10',
                'desk_moloni_queue_max_attempts' => '3',
                'desk_moloni_queue_retry_delay' => '300',
                'desk_moloni_enable_webhooks' => '1',
                'desk_moloni_webhook_timeout' => '30',
                'desk_moloni_webhook_max_retries' => '3',
                'desk_moloni_webhook_secret' => desk_moloni_generate_encryption_key(),
                'desk_moloni_enable_client_portal' => '0',
                'desk_moloni_client_can_download_pdfs' => '1',
                'desk_moloni_continue_on_error' => '1',
                'desk_moloni_max_consecutive_errors' => '5',
                'desk_moloni_enable_error_notifications' => '1',
                'desk_moloni_enable_rate_limiting' => '1',
                'desk_moloni_requests_per_minute' => '60',
                'desk_moloni_rate_limit_window' => '60',
                'desk_moloni_enable_redis' => '0',
                'desk_moloni_redis_host' => '127.0.0.1',
                'desk_moloni_redis_port' => '6379',
                'desk_moloni_redis_database' => '0',
                'desk_moloni_module_version' => DESK_MOLONI_VERSION,
                'desk_moloni_installation_date' => date('Y-m-d H:i:s'),
                'desk_moloni_last_update' => date('Y-m-d H:i:s')
            ];
            
            // Add each option only if it doesn't exist
            foreach ($default_options as $key => $value) {
                if (function_exists('get_option') && function_exists('add_option')) {
                    if (get_option($key) === false) {
                        add_option($key, $value);
                    }
                }
            }
            
            return true;
        } catch (Throwable $e) {
            error_log("Desk-Moloni configuration setup error: " . $e->getMessage());
            return false;
        }
    }
}

/**
 * Generate encryption key helper function
 */
if (!function_exists('desk_moloni_generate_encryption_key')) {
    function desk_moloni_generate_encryption_key($length = 32) {
        try {
            return bin2hex(random_bytes($length));
        } catch (Exception $e) {
            // Fallback for older systems
            return md5(uniqid(mt_rand(), true));
        }
    }
}

/**
 * BULLETPROOF PERMISSIONS MANAGEMENT
 */
if (!function_exists('desk_moloni_ensure_permissions_exist')) {
    function desk_moloni_ensure_permissions_exist()
    {
        try {
            $CI = &get_instance();
            $CI->load->database();
            
            // Check if permissions already exist
            $existing = $CI->db->get_where('tblpermissions', ['name' => 'desk_moloni'])->num_rows();
            
            if ($existing == 0) {
                $permissions = [
                    ['name' => 'desk_moloni', 'shortname' => 'view', 'description' => 'View Desk-Moloni module'],
                    ['name' => 'desk_moloni', 'shortname' => 'create', 'description' => 'Create sync tasks and configurations'],
                    ['name' => 'desk_moloni', 'shortname' => 'edit', 'description' => 'Edit configurations and mappings'],
                    ['name' => 'desk_moloni', 'shortname' => 'delete', 'description' => 'Delete sync tasks and clear data']
                ];
                
                foreach ($permissions as $permission) {
                    try {
                        $CI->db->insert('tblpermissions', $permission);
                    } catch (Exception $e) {
                        error_log("Error inserting permission: " . $e->getMessage());
                    }
                }
            }
            
            return true;
        } catch (Throwable $e) {
            error_log("Desk-Moloni permissions setup error: " . $e->getMessage());
            return false;
        }
    }
}

/**
 * Hook functions
 */

/**
 * Admin initialization hook with enhanced error handling for PHP 8.0+
 */
if (!function_exists('desk_moloni_admin_init_hook')) {
    function desk_moloni_admin_init_hook()
    {
        try {
            $CI = &get_instance();
            
            // Safely load module configuration
            if (method_exists($CI->load, 'config')) {
                $config_file = DESK_MOLONI_MODULE_PATH . '/config/config.php';
                if (file_exists($config_file)) {
                    $CI->load->config('desk_moloni/config');
                }
            }
            
            // Add CSS and JS for admin with file existence checks
            if (isset($CI->app_css) && method_exists($CI->app_css, 'add')) {
                $admin_css = DESK_MOLONI_MODULE_PATH . '/assets/css/admin.css';
                if (file_exists($admin_css)) {
                    $CI->app_css->add('desk-moloni-admin-css', base_url('modules/desk_moloni/assets/css/admin.css'));
                }
            }
            
            if (isset($CI->app_scripts) && method_exists($CI->app_scripts, 'add')) {
                $admin_js = DESK_MOLONI_MODULE_PATH . '/assets/js/admin.js';
                if (file_exists($admin_js)) {
                    $CI->app_scripts->add('desk-moloni-admin-js', base_url('modules/desk_moloni/assets/js/admin.js'));
                }
            }
        } catch (Throwable $e) {
            // Log error but don't break the application
            error_log("Desk-Moloni admin init error: " . $e->getMessage());
        }
    }
}

/**
 * Admin menu initialization with enhanced PHP 8.0+ error handling
 */
if (!function_exists('desk_moloni_init_admin_menu')) {
    function desk_moloni_init_admin_menu()
    {
        try {
            $CI = &get_instance();
            
            // Check permissions safely with function existence
            $has_permission = function_exists('has_permission') ? has_permission('desk_moloni', '', 'view') : false;
            
            if ($has_permission && isset($CI->app_menu) && method_exists($CI->app_menu, 'add_sidebar_menu_item')) {
                // Main menu item
                $CI->app_menu->add_sidebar_menu_item('desk-moloni', [
                    'name'     => 'Desk-Moloni',
                    'href'     => admin_url('desk_moloni/admin'),
                    'icon'     => 'fa fa-refresh',
                    'position' => 35,
                ]);
                
                // Define menu items with fallback text in case _l() function is not available
                $menu_items = [
                    [
                        'slug'     => 'desk-moloni-dashboard',
                        'name'     => function_exists('_l') ? _l('Dashboard') : 'Dashboard',
                        'href'     => admin_url('desk_moloni/dashboard'),
                        'position' => 1,
                    ],
                    [
                        'slug'     => 'desk-moloni-config',
                        'name'     => function_exists('_l') ? _l('Configuration') : 'Configuration',
                        'href'     => admin_url('desk_moloni/admin/config'),
                        'position' => 2,
                    ],
                    [
                        'slug'     => 'desk-moloni-sync',
                        'name'     => function_exists('_l') ? _l('Synchronization') : 'Synchronization',
                        'href'     => admin_url('desk_moloni/admin/manual_sync'),
                        'position' => 3,
                    ],
                    [
                        'slug'     => 'desk-moloni-queue',
                        'name'     => function_exists('_l') ? _l('Queue Status') : 'Queue Status',
                        'href'     => admin_url('desk_moloni/queue'),
                        'position' => 4,
                    ],
                    [
                        'slug'     => 'desk-moloni-mapping',
                        'name'     => function_exists('_l') ? _l('Mappings') : 'Mappings',
                        'href'     => admin_url('desk_moloni/mapping'),
                        'position' => 5,
                    ],
                    [
                        'slug'     => 'desk-moloni-logs',
                        'name'     => function_exists('_l') ? _l('Sync Logs') : 'Sync Logs',
                        'href'     => admin_url('desk_moloni/logs'),
                        'position' => 6,
                    ],
                ];
                
                // Add submenu items safely
                foreach ($menu_items as $item) {
                    if (method_exists($CI->app_menu, 'add_sidebar_children_item')) {
                        $CI->app_menu->add_sidebar_children_item('desk-moloni', $item);
                    }
                }
            }
        } catch (Throwable $e) {
            // Log error but continue execution
            error_log("Desk-Moloni menu init error: " . $e->getMessage());
        }
    }
}

function desk_moloni_client_init_hook()
{
    try {
        $CI = &get_instance();
        
        // Add client portal CSS and JS with file existence checks
        if (isset($CI->app_css) && method_exists($CI->app_css, 'add')) {
            $client_css = DESK_MOLONI_MODULE_PATH . '/assets/css/client.css';
            if (file_exists($client_css)) {
                $CI->app_css->add('desk-moloni-client-css', base_url('modules/desk_moloni/assets/css/client.css'));
            }
        }
        
        if (isset($CI->app_scripts) && method_exists($CI->app_scripts, 'add')) {
            $client_js = DESK_MOLONI_MODULE_PATH . '/client_portal/dist/js/app.js';
            if (file_exists($client_js)) {
                $CI->app_scripts->add('desk-moloni-client-js', base_url('modules/desk_moloni/client_portal/dist/js/app.js'));
            }
        }
        
        // Add client portal tab
        if (function_exists('hooks')) {
            hooks()->add_action('clients_navigation_end', 'desk_moloni_add_client_tab');
        }
    } catch (Throwable $e) {
        error_log("Desk-Moloni client init error: " . $e->getMessage());
    }
}

function desk_moloni_add_client_tab()
{
    try {
        $CI = &get_instance();
        echo '<li role="presentation">';
        echo '<a href="' . site_url('clients/desk_moloni') . '" aria-controls="desk_moloni" role="tab" data-toggle="tab">';
        echo '<i class="fa fa-file-text-o"></i> ' . (function_exists('_l') ? _l('My Documents') : 'My Documents');
        echo '</a>';
        echo '</li>';
    } catch (Throwable $e) {
        error_log("Desk-Moloni client tab error: " . $e->getMessage());
    }
}

/**
 * Synchronization hook functions
 */

function desk_moloni_sync_customer_added($customer_id)
{
    desk_moloni_add_sync_task('sync_client', 'client', $customer_id);
}

function desk_moloni_sync_customer_updated($customer_id)
{
    desk_moloni_add_sync_task('sync_client', 'client', $customer_id);
}

function desk_moloni_sync_invoice_added($invoice_id)
{
    desk_moloni_add_sync_task('sync_invoice', 'invoice', $invoice_id);
}

function desk_moloni_sync_invoice_updated($invoice_id)
{
    desk_moloni_add_sync_task('sync_invoice', 'invoice', $invoice_id);
}

function desk_moloni_sync_estimate_added($estimate_id)
{
    desk_moloni_add_sync_task('sync_estimate', 'estimate', $estimate_id);
}

function desk_moloni_sync_estimate_updated($estimate_id)
{
    desk_moloni_add_sync_task('sync_estimate', 'estimate', $estimate_id);
}

function desk_moloni_sync_item_added($item_id)
{
    desk_moloni_add_sync_task('sync_product', 'product', $item_id);
}

function desk_moloni_sync_item_updated($item_id)
{
    desk_moloni_add_sync_task('sync_product', 'product', $item_id);
}

/**
 * Add task to sync queue
 */
/**
 * Add task to sync queue with PHP 8.0+ null coalescing and error handling
 */
if (!function_exists('desk_moloni_add_sync_task')) {
    function desk_moloni_add_sync_task($task_type, $entity_type, $entity_id, $priority = 5)
    {
        try {
            $CI = &get_instance();
            
            // Enhanced null checks using PHP 8.0+ null coalescing operator
            $sync_enabled = function_exists('get_option') ? (get_option('desk_moloni_sync_enabled') ?? false) : false;
            if (!$sync_enabled) {
                return false;
            }
            
            // Check if specific entity sync is enabled with PHP 8.0+ string operations
            $entity_sync_key = 'desk_moloni_auto_sync_' . $entity_type . 's';
            $entity_sync_enabled = function_exists('get_option') ? (get_option($entity_sync_key) ?? false) : false;
            if (!$entity_sync_enabled) {
                return false;
            }
            
            // Load sync queue model with error handling
            if (method_exists($CI->load, 'model')) {
                $CI->load->model('desk_moloni/sync_queue_model');
                
                // Add task to queue with method existence check
                if (isset($CI->sync_queue_model) && method_exists($CI->sync_queue_model, 'add_task')) {
                    return $CI->sync_queue_model->add_task($task_type, $entity_type, $entity_id, $priority);
                }
            }
            
            return false;
        } catch (Throwable $e) {
            error_log("Desk-Moloni add sync task error: " . $e->getMessage());
            return false;
        }
    }
}

/**
 * Client portal route handler
 */
function desk_moloni_client_portal_route()
{
    try {
        $CI = &get_instance();
        
        // Check if client is logged in
        if (!function_exists('is_client_logged_in') || !is_client_logged_in()) {
            if (function_exists('redirect')) {
                redirect("clients/login");
            }
            return;
        }
        
        // Load the client portal view
        $CI->load->view("desk_moloni/client_portal/index");
    } catch (Throwable $e) {
        error_log("Desk-Moloni client portal error: " . $e->getMessage());
    }
}

/**
 * Register client portal routes
 */
if (function_exists('hooks')) {
    hooks()->add_action("clients_init", function() {
        try {
            $CI = &get_instance();
            
            // Register the main client portal route
            if (isset($CI->router) && property_exists($CI->router, 'route') && is_array($CI->router->route)) {
                $CI->router->route["clients/desk_moloni"] = "desk_moloni_client_portal_route";
            }
        } catch (Throwable $e) {
            error_log("Desk-Moloni client route error: " . $e->getMessage());
        }
    });
}
