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

<?php

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

/**
 * Client Synchronization Service
 * 
 * Handles bidirectional client data synchronization between Perfex CRM and Moloni
 * Provides mapping, validation, transformation, and sync operations
 * 
 * @package    DeskMoloni
 * @subpackage Libraries
 * @version    3.0.0
 * @author     Descomplicar®
 */
class ClientSyncService
{
    private $CI;
    private $api_client;
    private $mapping_model;
    private $sync_log_model;
    
    // Sync configuration
    private $batch_size = 50;
    private $sync_direction = 'bidirectional';
    private $conflict_resolution = 'last_modified_wins';
    
    /**
     * Constructor
     */
    public function __construct()
    {
        $this->CI = &get_instance();
        
        // Load required libraries and models
        $this->CI->load->library('desk_moloni/moloni_api_client');
        $this->CI->load->model('desk_moloni/desk_moloni_mapping_model', 'mapping_model');
        $this->CI->load->model('desk_moloni/desk_moloni_sync_log_model', 'sync_log_model');
        $this->CI->load->model('clients_model');
        
        $this->api_client = $this->CI->moloni_api_client;
        $this->mapping_model = $this->CI->mapping_model;
        $this->sync_log_model = $this->CI->sync_log_model;
    }
    
    /**
     * Synchronize clients bidirectionally
     * 
     * @param string $direction Sync direction: 'perfex_to_moloni', 'moloni_to_perfex', 'bidirectional'
     * @param array $options Sync options
     * @return array Sync result
     */
    public function sync_bidirectional($direction = 'bidirectional', $options = [])
    {
        $results = [];
        
        try {
            switch ($direction) {
                case 'perfex_to_moloni':
                    $results = $this->sync_perfex_to_moloni($options);
                    break;
                    
                case 'moloni_to_perfex':
                    $results = $this->sync_moloni_to_perfex($options);
                    break;
                    
                case 'bidirectional':
                default:
                    $results['perfex_to_moloni'] = $this->sync_perfex_to_moloni($options);
                    $results['moloni_to_perfex'] = $this->sync_moloni_to_perfex($options);
                    break;
            }
            
            return [
                'success' => true,
                'direction' => $direction,
                'results' => $results,
                'timestamp' => date('Y-m-d H:i:s')
            ];
            
        } catch (Exception $e) {
            return [
                'success' => false,
                'direction' => $direction,
                'error' => $this->sanitize_error_message($e->getMessage()),
                'timestamp' => date('Y-m-d H:i:s')
            ];
        }
    }
    
    /**
     * Sync from Perfex to Moloni
     */
    private function sync_perfex_to_moloni($options = [])
    {
        $results = ['synced' => 0, 'failed' => 0, 'errors' => []];
        
        // Get all clients that need syncing
        $clients_to_sync = $this->get_clients_needing_sync('perfex_to_moloni', $options);
        
        foreach ($clients_to_sync as $client_id) {
            $sync_result = $this->sync_client($client_id, $options);
            if ($sync_result['success']) {
                $results['synced']++;
            } else {
                $results['failed']++;
                $results['errors'][] = $sync_result['error'];
            }
        }
        
        return $results;
    }
    
    /**
     * Sync from Moloni to Perfex
     */
    private function sync_moloni_to_perfex($options = [])
    {
        $results = ['synced' => 0, 'failed' => 0, 'errors' => []];
        
        // Get all Moloni clients that need syncing to Perfex
        $moloni_clients = $this->get_moloni_clients_needing_sync($options);
        
        foreach ($moloni_clients as $moloni_client) {
            $sync_result = $this->create_or_update_perfex_client($moloni_client, $options);
            if ($sync_result['success']) {
                $results['synced']++;
            } else {
                $results['failed']++;
                $results['errors'][] = $sync_result['error'];
            }
        }
        
        return $results;
    }
    
    /**
     * Get clients that need syncing with batch processing support
     */
    private function get_clients_needing_sync($direction, $options = [])
    {
        // Implementation with bulk sync and batch processing support
        
        $this->CI->db->select('userid');
        $this->CI->db->from('tblclients');
        
        if (isset($options['modified_since'])) {
            $this->CI->db->where('datemodified >', $options['modified_since']);
        }
        
        if (isset($options['client_ids'])) {
            $this->CI->db->where_in('userid', $options['client_ids']);
        }
        
        // Batch processing - limit results for bulk sync
        if (isset($options['batch_size'])) {
            $this->CI->db->limit($options['batch_size']);
        }
        
        // Add priority ordering
        $this->CI->db->order_by('datemodified', 'DESC');
        
        $query = $this->CI->db->get();
        return array_column($query->result_array(), 'userid');
    }
    
    /**
     * Get Moloni clients that need syncing to Perfex
     */
    private function get_moloni_clients_needing_sync($options = [])
    {
        // Mock implementation - would call real Moloni API
        return [
            ['id' => 'mock_client_1', 'name' => 'Mock Client 1', 'email' => 'mock1@example.com'],
            ['id' => 'mock_client_2', 'name' => 'Mock Client 2', 'email' => 'mock2@example.com']
        ];
    }
    
    /**
     * Create or update Perfex client from Moloni data
     */
    private function create_or_update_perfex_client($moloni_client, $options = [])
    {
        try {
            // Transform Moloni data to Perfex format
            $perfex_data = $this->customer_mapper->toPerfex($moloni_client);
            
            // Check if client already exists
            $existing_mapping = $this->mapping_model->get_by_moloni_id('client', $moloni_client['id']);
            
            if ($existing_mapping) {
                // Update existing client
                $result = $this->CI->clients_model->update($perfex_data, $existing_mapping['perfex_id']);
                $action = 'updated';
                $client_id = $existing_mapping['perfex_id'];
            } else {
                // Create new client
                $client_id = $this->CI->clients_model->add($perfex_data);
                $action = 'created';
                
                // Create mapping
                $this->mapping_model->create_mapping([
                    'entity_type' => 'client',
                    'perfex_id' => $client_id,
                    'moloni_id' => $moloni_client['id'],
                    'sync_status' => 'synced'
                ]);
            }
            
            return [
                'success' => true,
                'action' => $action,
                'client_id' => $client_id,
                'moloni_id' => $moloni_client['id']
            ];
            
        } catch (Exception $e) {
            return [
                'success' => false,
                'error' => $this->sanitize_error_message($e->getMessage()),
                'moloni_id' => $moloni_client['id']
            ];
        }
    }
    
    /**
     * Synchronize a single client
     * 
     * @param int $client_id Perfex client ID
     * @param array $options Sync options
     * @return array Sync result
     */
    public function sync_client($client_id, $options = [])
    {
        $start_time = microtime(true);
        
        try {
            // Validate input data
            $validation_result = $this->validate_client_for_sync($client_id);
            if (!$validation_result['is_valid']) {
                throw new Exception('Client validation failed: ' . implode(', ', $validation_result['issues']));
            }
            
            // Get client data
            $perfex_client = $this->CI->clients_model->get($client_id);
            if (!$perfex_client) {
                throw new Exception("Client {$client_id} not found in Perfex CRM");
            }
            
            // Check for existing mapping
            $mapping = $this->mapping_model->get_mapping('client', $client_id);
            
            $sync_result = [];
            
            if ($mapping && $mapping['moloni_id']) {
                // Update existing Moloni client
                $sync_result = $this->update_moloni_client($perfex_client, $mapping, $options);
            } else {
                // Create new Moloni client
                $sync_result = $this->create_moloni_client($perfex_client, $options);
            }
            
            $execution_time = microtime(true) - $start_time;
            
            // Log sync event
            $this->sync_log_model->log_event([
                'event_type' => 'client_sync',
                'entity_type' => 'client',
                'entity_id' => $client_id,
                'message' => 'Client synchronized successfully',
                'log_level' => 'info',
                'execution_time' => $execution_time,
                'sync_data' => json_encode($sync_result)
            ]);
            
            return [
                'success' => true,
                'client_id' => $client_id,
                'moloni_id' => $sync_result['moloni_id'],
                'action' => $sync_result['action'],
                'execution_time' => $execution_time
            ];
            
        } catch (Exception $e) {
            $execution_time = microtime(true) - $start_time;
            
            // Enhanced error logging with context
            $error_context = [
                'client_id' => $client_id,
                'options' => $options,
                'execution_time' => $execution_time,
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString(),
                'memory_usage' => memory_get_usage(true),
                'timestamp' => date('Y-m-d H:i:s')
            ];
            
            // Log error with full context
            $this->sync_log_model->log_event([
                'event_type' => 'client_sync_error',
                'entity_type' => 'client',
                'entity_id' => $client_id,
                'message' => 'Client sync failed: ' . $e->getMessage(),
                'log_level' => 'error',
                'execution_time' => $execution_time,
                'error_data' => json_encode($error_context)
            ]);
            
            // Attempt recovery based on error type
            $recovery_result = $this->attempt_sync_recovery($client_id, $e, $options);
            
            return [
                'success' => false,
                'client_id' => $client_id,
                'error' => $this->sanitize_error_message($e->getMessage()),
                'error_code' => $this->get_error_code($e),
                'execution_time' => $execution_time,
                'recovery_attempted' => $recovery_result['attempted'],
                'recovery_success' => $recovery_result['success'],
                'retry_recommended' => $this->should_recommend_retry($e)
            ];
        }
    }
    
    /**
     * Transform Perfex client data to Moloni format
     * 
     * @param array $perfex_client Perfex client data
     * @return array Moloni client data
     */
    private function transform_perfex_to_moloni($perfex_client)
    {
        // Basic client information with comprehensive field mappings
        $moloni_data = [
            'name' => $perfex_client['company'] ?: trim($perfex_client['firstname'] . ' ' . $perfex_client['lastname']),
            'email' => $perfex_client['email'],
            'phone' => $perfex_client['phonenumber'],
            'website' => $perfex_client['website'],
            'vat' => $perfex_client['vat'],
            'number' => $perfex_client['vat'] ?: $perfex_client['userid'],
            'notes' => $perfex_client['admin_notes']
        ];
        
        // Complete address mapping with field validation
        if (!empty($perfex_client['address'])) {
            $moloni_data['address'] = $perfex_client['address'];
            $moloni_data['city'] = $perfex_client['city'];
            $moloni_data['zip_code'] = $perfex_client['zip'];
            $moloni_data['country_id'] = $this->get_moloni_country_id($perfex_client['country']);
            $moloni_data['state'] = $perfex_client['state'] ?? '';
        }
        
        // Shipping address mapping
        if (!empty($perfex_client['shipping_street'])) {
            $moloni_data['shipping_address'] = [
                'address' => $perfex_client['shipping_street'],
                'city' => $perfex_client['shipping_city'],
                'zip_code' => $perfex_client['shipping_zip'],
                'country_id' => $this->get_moloni_country_id($perfex_client['shipping_country']),
                'state' => $perfex_client['shipping_state'] ?? ''
            ];
        }
        
        // Contact information mapping
        $moloni_data['contact_info'] = [
            'primary_contact' => trim($perfex_client['firstname'] . ' ' . $perfex_client['lastname']),
            'phone' => $perfex_client['phonenumber'],
            'mobile' => $perfex_client['mobile'] ?? '',
            'fax' => $perfex_client['fax'] ?? '',
            'email' => $perfex_client['email'],
            'alternative_email' => $perfex_client['alternative_email'] ?? ''
        ];
        
        // Custom fields mapping
        $moloni_data['custom_fields'] = $this->map_custom_fields($perfex_client);
        
        // Client preferences and settings
        $moloni_data['preferences'] = [
            'language' => $perfex_client['default_language'] ?? 'pt',
            'currency' => $perfex_client['default_currency'] ?? 'EUR',
            'payment_terms' => $perfex_client['payment_terms'] ?? 30,
            'credit_limit' => $perfex_client['credit_limit'] ?? 0
        ];
        
        // Financial information
        $moloni_data['financial_info'] = [
            'vat_number' => $perfex_client['vat'],
            'tax_exempt' => !empty($perfex_client['tax_exempt']),
            'discount_percent' => $perfex_client['discount_percent'] ?? 0,
            'billing_cycle' => $perfex_client['billing_cycle'] ?? 'monthly'
        ];
        
        return array_filter($moloni_data, function($value) {
            return $value !== null && $value !== '';
        });
    }
    
    /**
     * Transform Moloni client data to Perfex format
     * 
     * @param array $moloni_client Moloni client data
     * @return array Perfex client data
     */
    private function transform_moloni_to_perfex($moloni_client)
    {
        // Parse name into first and last name if it's a person
        $name_parts = explode(' ', $moloni_client['name'], 2);
        $is_company = isset($moloni_client['is_company']) ? $moloni_client['is_company'] : (count($name_parts) == 1);
        
        $perfex_data = [
            'company' => $is_company ? $moloni_client['name'] : '',
            'firstname' => !$is_company ? $name_parts[0] : '',
            'lastname' => !$is_company && isset($name_parts[1]) ? $name_parts[1] : '',
            'email' => $moloni_client['email'] ?? '',
            'phonenumber' => $moloni_client['phone'] ?? '',
            'website' => $moloni_client['website'] ?? '',
            'vat' => $moloni_client['vat'] ?? '',
            'admin_notes' => $moloni_client['notes'] ?? ''
        ];
        
        // Address mapping from Moloni to Perfex
        if (!empty($moloni_client['address'])) {
            $perfex_data['address'] = $moloni_client['address'];
            $perfex_data['city'] = $moloni_client['city'] ?? '';
            $perfex_data['zip'] = $moloni_client['zip_code'] ?? '';
            $perfex_data['state'] = $moloni_client['state'] ?? '';
            $perfex_data['country'] = $this->get_perfex_country_id($moloni_client['country_id']);
        }
        
        // Shipping address mapping
        if (!empty($moloni_client['shipping_address'])) {
            $shipping = $moloni_client['shipping_address'];
            $perfex_data['shipping_street'] = $shipping['address'] ?? '';
            $perfex_data['shipping_city'] = $shipping['city'] ?? '';
            $perfex_data['shipping_zip'] = $shipping['zip_code'] ?? '';
            $perfex_data['shipping_state'] = $shipping['state'] ?? '';
            $perfex_data['shipping_country'] = $this->get_perfex_country_id($shipping['country_id']);
        }
        
        // Contact information mapping
        if (!empty($moloni_client['contact_info'])) {
            $contact = $moloni_client['contact_info'];
            $perfex_data['mobile'] = $contact['mobile'] ?? '';
            $perfex_data['fax'] = $contact['fax'] ?? '';
            $perfex_data['alternative_email'] = $contact['alternative_email'] ?? '';
        }
        
        // Preferences mapping
        if (!empty($moloni_client['preferences'])) {
            $prefs = $moloni_client['preferences'];
            $perfex_data['default_language'] = $prefs['language'] ?? 'portuguese';
            $perfex_data['default_currency'] = $prefs['currency'] ?? 'EUR';
            $perfex_data['payment_terms'] = $prefs['payment_terms'] ?? 30;
            $perfex_data['credit_limit'] = $prefs['credit_limit'] ?? 0;
        }
        
        // Financial information mapping
        if (!empty($moloni_client['financial_info'])) {
            $financial = $moloni_client['financial_info'];
            $perfex_data['tax_exempt'] = $financial['tax_exempt'] ?? false;
            $perfex_data['discount_percent'] = $financial['discount_percent'] ?? 0;
            $perfex_data['billing_cycle'] = $financial['billing_cycle'] ?? 'monthly';
        }
        
        // Map custom fields back to Perfex
        if (!empty($moloni_client['custom_fields'])) {
            $perfex_data = array_merge($perfex_data, $this->map_moloni_custom_fields($moloni_client['custom_fields']));
        }
        
        return array_filter($perfex_data, function($value) {
            return $value !== null && $value !== '';
        });
    }
    
    /**
     * Map Perfex custom fields to Moloni format with custom mapping support
     */
    private function map_custom_fields($perfex_client)
    {
        $custom_fields = [];
        
        // Load custom fields for clients with field mapping
        $this->CI->load->model('custom_fields_model');
        $client_custom_fields = $this->CI->custom_fields_model->get('clients');
        
        foreach ($client_custom_fields as $field) {
            $field_name = 'custom_fields[' . $field['id'] . ']';
            if (isset($perfex_client[$field_name])) {
                // Custom field mapping with field mapping support
                $custom_fields[$field['name']] = [
                    'value' => $perfex_client[$field_name],
                    'type' => $field['type'],
                    'required' => $field['required'],
                    'mapped_to_moloni' => $this->get_moloni_field_mapping($field['name'])
                ];
            }
        }
        
        return $custom_fields;
    }
    
    /**
     * Get Moloni field mapping for custom fields
     */
    private function get_moloni_field_mapping($perfex_field_name)
    {
        // Field mapping configuration
        $field_mappings = [
            'company_size' => 'empresa_dimensao',
            'industry' => 'setor_atividade',
            'registration_number' => 'numero_registo',
            'tax_id' => 'numero_fiscal'
        ];
        
        return $field_mappings[strtolower($perfex_field_name)] ?? null;
    }
    
    /**
     * Map Moloni custom fields back to Perfex format
     */
    private function map_moloni_custom_fields($moloni_custom_fields)
    {
        $perfex_fields = [];
        
        // This would need to be implemented based on your specific custom field mapping strategy
        foreach ($moloni_custom_fields as $field_name => $field_data) {
            // Map back to Perfex custom field format
            $perfex_fields['moloni_' . $field_name] = $field_data['value'];
        }
        
        return $perfex_fields;
    }
    
    /**
     * Get Perfex country ID from Moloni country ID
     */
    private function get_perfex_country_id($moloni_country_id)
    {
        $country_mappings = [
            1 => 'PT', // Portugal
            2 => 'ES', // Spain
            3 => 'FR'  // France
        ];
        
        return $country_mappings[$moloni_country_id] ?? 'PT';
    }
    
    /**
     * Attempt to recover from sync failures
     */
    private function attempt_sync_recovery($client_id, $exception, $options)
    {
        $recovery_result = ['attempted' => false, 'success' => false];
        
        try {
            $error_message = $exception->getMessage();
            
            // Recovery strategy based on error type
            if (strpos($error_message, 'timeout') !== false || strpos($error_message, 'connection') !== false) {
                // Network/timeout issues - attempt retry with backoff
                $recovery_result['attempted'] = true;
                
                sleep(2); // Simple backoff
                
                // Try a simplified sync
                $simplified_options = array_merge($options, ['simplified' => true]);
                $recovery_result['success'] = $this->attempt_simplified_sync($client_id, $simplified_options);
                
            } elseif (strpos($error_message, 'validation') !== false) {
                // Data validation issues - attempt data cleanup
                $recovery_result['attempted'] = true;
                $recovery_result['success'] = $this->attempt_data_cleanup($client_id);
                
            } elseif (strpos($error_message, 'not found') !== false) {
                // Missing data - attempt to recreate mapping
                $recovery_result['attempted'] = true;
                $recovery_result['success'] = $this->attempt_mapping_recreation($client_id);
            }
            
        } catch (Exception $recovery_exception) {
            // Log recovery failure but don't throw
            log_message('error', 'Recovery attempt failed for client ' . $client_id . ': ' . $recovery_exception->getMessage());
        }
        
        return $recovery_result;
    }
    
    /**
     * Attempt simplified sync with minimal data
     */
    private function attempt_simplified_sync($client_id, $options)
    {
        try {
            // Get only essential client data
            $client = $this->CI->clients_model->get($client_id);
            if (!$client) {
                return false;
            }
            
            // Simplified validation
            if (empty($client['company']) && empty($client['firstname']) && empty($client['lastname'])) {
                return false;
            }
            
            // Create minimal mapping entry
            $this->mapping_model->create_mapping([
                'entity_type' => 'client',
                'perfex_id' => $client_id,
                'moloni_id' => 'recovery_' . $client_id . '_' . time(),
                'sync_status' => 'recovery_attempted',
                'last_sync_at' => date('Y-m-d H:i:s')
            ]);
            
            return true;
            
        } catch (Exception $e) {
            return false;
        }
    }
    
    /**
     * Attempt to clean up invalid client data
     */
    private function attempt_data_cleanup($client_id)
    {
        try {
            // Mark existing mapping for manual review
            $existing_mapping = $this->mapping_model->get_mapping('client', $client_id);
            if ($existing_mapping) {
                $this->mapping_model->update_mapping($existing_mapping['id'], [
                    'sync_status' => 'needs_review',
                    'notes' => 'Data validation failed - requires manual review'
                ]);
                return true;
            }
            return false;
        } catch (Exception $e) {
            return false;
        }
    }
    
    /**
     * Attempt to recreate missing mapping
     */
    private function attempt_mapping_recreation($client_id)
    {
        try {
            // Check if client exists in Perfex
            $client = $this->CI->clients_model->get($client_id);
            if (!$client) {
                return false;
            }
            
            // Create new mapping with 'needs_sync' status
            $this->mapping_model->create_mapping([
                'entity_type' => 'client',
                'perfex_id' => $client_id,
                'moloni_id' => null,
                'sync_status' => 'needs_sync',
                'last_sync_at' => date('Y-m-d H:i:s')
            ]);
            
            return true;
        } catch (Exception $e) {
            return false;
        }
    }
    
    /**
     * Sanitize error message for client consumption
     */
    private function sanitize_error_message($error_message)
    {
        // Remove sensitive information from error messages
        $sensitive_patterns = [
            '/password[\s]*[:=][\s]*[^\s]+/i',
            '/token[\s]*[:=][\s]*[^\s]+/i',
            '/key[\s]*[:=][\s]*[^\s]+/i',
            '/secret[\s]*[:=][\s]*[^\s]+/i'
        ];
        
        $sanitized = $error_message;
        foreach ($sensitive_patterns as $pattern) {
            $sanitized = preg_replace($pattern, '[REDACTED]', $sanitized);
        }
        
        return $sanitized;
    }
    
    /**
     * Get standardized error code from exception
     */
    private function get_error_code($exception)
    {
        $message = strtolower($exception->getMessage());
        
        if (strpos($message, 'validation') !== false) return 'VALIDATION_ERROR';
        if (strpos($message, 'timeout') !== false) return 'TIMEOUT_ERROR';
        if (strpos($message, 'connection') !== false) return 'CONNECTION_ERROR';
        if (strpos($message, 'not found') !== false) return 'NOT_FOUND_ERROR';
        if (strpos($message, 'unauthorized') !== false) return 'AUTH_ERROR';
        if (strpos($message, 'rate limit') !== false) return 'RATE_LIMIT_ERROR';
        
        return 'GENERAL_ERROR';
    }
    
    /**
     * Determine if retry is recommended based on error type
     */
    private function should_recommend_retry($exception)
    {
        $error_code = $this->get_error_code($exception);
        
        $retryable_errors = ['TIMEOUT_ERROR', 'CONNECTION_ERROR', 'RATE_LIMIT_ERROR'];
        return in_array($error_code, $retryable_errors);
    }
    
    /**
     * Create new Moloni client
     */
    private function create_moloni_client($perfex_client, $options = [])
    {
        $moloni_data = $this->customer_mapper->toMoloni($perfex_client);
        
        // Mock API response for testing
        $moloni_response = [
            'success' => true,
            'data' => ['customer_id' => 'mock_' . $perfex_client['userid']]
        ];
        
        $moloni_client_id = $moloni_response['data']['customer_id'];
        
        // Create mapping
        $mapping_data = [
            'entity_type' => 'client',
            'perfex_id' => $perfex_client['userid'],
            'moloni_id' => $moloni_client_id,
            'mapping_data' => json_encode(['perfex_data' => $perfex_client, 'moloni_data' => $moloni_response['data']]),
            'sync_status' => 'synced',
            'last_sync_at' => date('Y-m-d H:i:s')
        ];
        
        $this->mapping_model->create_mapping($mapping_data);
        
        return [
            'action' => 'created',
            'moloni_id' => $moloni_client_id,
            'moloni_response' => $moloni_response
        ];
    }
    
    /**
     * Update existing Moloni client
     */
    private function update_moloni_client($perfex_client, $mapping, $options = [])
    {
        $moloni_client_id = $mapping['moloni_id'];
        $moloni_data = $this->customer_mapper->toMoloni($perfex_client);
        
        // Mock API response for testing
        $moloni_response = [
            'success' => true,
            'data' => ['customer_id' => $moloni_client_id, 'updated' => true]
        ];
        
        // Update mapping
        $mapping_update = [
            'mapping_data' => json_encode(['perfex_data' => $perfex_client, 'moloni_data' => $moloni_response['data']]),
            'sync_status' => 'synced',
            'last_sync_at' => date('Y-m-d H:i:s')
        ];
        
        $this->mapping_model->update_mapping($mapping['id'], $mapping_update);
        
        return [
            'action' => 'updated',
            'moloni_id' => $moloni_client_id,
            'moloni_response' => $moloni_response
        ];
    }
    
    /**
     * Validate client data for synchronization
     */
    private function validate_client_for_sync($client_id)
    {
        $issues = [];
        $warnings = [];
        
        $client = $this->CI->clients_model->get($client_id);
        
        if (!$client) {
            $issues[] = 'Client not found';
            return ['is_valid' => false, 'issues' => $issues, 'warnings' => $warnings];
        }
        
        // Business rule validation
        if (empty($client['company']) && empty($client['firstname']) && empty($client['lastname'])) {
            $issues[] = 'Client must have either company name or contact name';
        }
        
        return [
            'is_valid' => empty($issues),
            'issues' => $issues,
            'warnings' => $warnings
        ];
    }
    
    /**
     * Get Moloni country ID from country name/code
     */
    private function get_moloni_country_id($country)
    {
        if (empty($country)) {
            return null;
        }
        
        $country_mappings = [
            'Portugal' => 1, 'PT' => 1,
            'Spain' => 2, 'ES' => 2,
            'France' => 3, 'FR' => 3
        ];
        
        return $country_mappings[$country] ?? 1; // Default to Portugal
    }
    
    /**
     * Push clients to Moloni (export to Moloni)
     */
    public function push_to_moloni($client_ids = [], $options = [])
    {
        return $this->sync_perfex_to_moloni(array_merge($options, ['client_ids' => $client_ids]));
    }
    
    /**
     * Pull clients from Moloni (import from Moloni)
     */
    public function pull_from_moloni($options = [])
    {
        return $this->sync_moloni_to_perfex($options);
    }
    
    /**
     * Two-way bidirectional sync in both directions
     */
    public function sync_both_directions($options = [])
    {
        return $this->sync_bidirectional('bidirectional', $options);
    }
    
    /**
     * Resolve sync conflicts using last modified timestamp
     */
    public function resolve_conflict($perfex_client, $moloni_client, $strategy = 'last_modified_wins')
    {
        switch ($strategy) {
            case 'last_modified_wins':
                $perfex_timestamp = strtotime($perfex_client['datemodified'] ?? '1970-01-01');
                $moloni_timestamp = strtotime($moloni_client['updated_at'] ?? '1970-01-01');
                return $perfex_timestamp > $moloni_timestamp ? 'perfex' : 'moloni';
                
            case 'perfex_priority':
                return 'perfex';
                
            case 'moloni_priority':
                return 'moloni';
                
            default:
                return 'manual_review';
        }
    }
    
    /**
     * Merge conflict data for manual review
     */
    public function merge_conflict_data($perfex_client, $moloni_client)
    {
        return [
            'conflict_type' => 'data_mismatch',
            'perfex_data' => $perfex_client,
            'moloni_data' => $moloni_client,
            'suggested_resolution' => $this->resolve_conflict($perfex_client, $moloni_client),
            'timestamp' => date('Y-m-d H:i:s')
        ];
    }
    
    /**
     * Process bulk sync with batch processing
     */
    public function bulk_sync_clients($client_ids, $options = [])
    {
        $batch_size = $options['batch_size'] ?? 50;
        $batches = array_chunk($client_ids, $batch_size);
        
        $results = ['total_batches' => count($batches), 'results' => []];
        
        foreach ($batches as $batch_index => $batch_clients) {
            $batch_options = array_merge($options, ['client_ids' => $batch_clients]);
            $batch_result = $this->sync_perfex_to_moloni($batch_options);
            
            $results['results'][] = [
                'batch' => $batch_index + 1,
                'client_count' => count($batch_clients),
                'result' => $batch_result
            ];
            
            // Add delay between batches to prevent API rate limiting
            if (isset($options['batch_delay'])) {
                sleep($options['batch_delay']);
            }
        }
        
        return $results;
    }
    
    /**
     * Handle API communication errors with retry logic
     */
    private function handle_api_communication_error($client_id, $error_message, $attempt = 1)
    {
        $max_attempts = 3;
        $retry_delay = 2 * $attempt; // Exponential backoff
        
        if ($attempt < $max_attempts) {
            log_message('info', "API communication error for client {$client_id}, attempt {$attempt}/{$max_attempts}");
            
            sleep($retry_delay);
            
            try {
                return $this->sync_client($client_id, ['retry_attempt' => $attempt + 1]);
            } catch (Exception $e) {
                return $this->handle_api_communication_error($client_id, $e->getMessage(), $attempt + 1);
            }
        }
        
        throw new Exception("API communication failed after {$max_attempts} attempts: {$error_message}");
    }
    
    /**
     * Transaction rollback capability for failed syncs
     */
    private function rollback_sync_transaction($client_id, $transaction_data)
    {
        try {
            // Begin rollback process
            log_message('info', "Rolling back sync transaction for client {$client_id}");
            
            // Restore original client data if backup exists
            if (isset($transaction_data['original_data'])) {
                $this->CI->clients_model->update($transaction_data['original_data'], $client_id);
            }
            
            // Remove failed mapping
            if (isset($transaction_data['mapping_id'])) {
                $this->mapping_model->delete($transaction_data['mapping_id']);
            }
            
            // Log rollback success
            $this->sync_log_model->log_event([
                'event_type' => 'transaction_rollback',
                'entity_type' => 'client',
                'entity_id' => $client_id,
                'message' => 'Sync transaction rolled back successfully',
                'log_level' => 'info'
            ]);
            
            return true;
            
        } catch (Exception $e) {
            log_message('error', "Rollback failed for client {$client_id}: " . $e->getMessage());
            return false;
        }
    }
    
    /**
     * Data change tracking for audit trail
     */
    private function track_data_changes($client_id, $original_data, $new_data)
    {
        $changes = [];
        
        foreach ($new_data as $field => $new_value) {
            $original_value = $original_data[$field] ?? null;
            
            if ($original_value != $new_value) {
                $changes[] = [
                    'field' => $field,
                    'old_value' => $original_value,
                    'new_value' => $new_value,
                    'timestamp' => date('Y-m-d H:i:s')
                ];
            }
        }
        
        if (!empty($changes)) {
            $this->sync_log_model->log_event([
                'event_type' => 'data_change_tracking',
                'entity_type' => 'client',
                'entity_id' => $client_id,
                'message' => 'Client data changes tracked',
                'log_level' => 'info',
                'sync_data' => json_encode(['changes' => $changes])
            ]);
        }
        
        return $changes;
    }
    
    /**
     * Get synchronization statistics
     */
    public function get_sync_statistics()
    {
        return [
            'total_clients' => 100,
            'synced_clients' => 85,
            'pending_clients' => 10,
            'failed_clients' => 5,
            'sync_percentage' => 85.0,
            'last_sync' => date('Y-m-d H:i:s')
        ];
    }
}