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

<?php

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

/**
 * Desk-Moloni Mapping Controller
 * Handles entity mapping management interface
 * 
 * @package    Desk-Moloni
 * @version    3.0.0
 * @author     Descomplicar Business Solutions
 */
class Mapping extends AdminController
{
    public function __construct()
    {
        parent::__construct();
        
        // Check if user is authenticated
        if (!is_staff_logged_in()) {
            redirect(admin_url('authentication'));
        }
        
        // Load models with correct names
        $this->load->model('desk_moloni/desk_moloni_config_model', 'config_model');
        $this->load->model('desk_moloni/desk_moloni_sync_queue_model', 'queue_model');
        $this->load->model('desk_moloni/desk_moloni_mapping_model', 'mapping_model');
        $this->load->model('desk_moloni/desk_moloni_sync_log_model', 'sync_log_model');
        $this->load->helper('desk_moloni');
        $this->load->library('form_validation');
    }

    /**
     * Mapping management interface
     */
    public function index()
    {
        if (!has_permission('desk_moloni', '', 'view')) {
            access_denied('desk_moloni');
        }

        $data = [
            'title' => _l('desk_moloni_mapping_management'),
            'entity_types' => ['client', 'product', 'invoice', 'estimate', 'credit_note'],
            'mapping_stats' => $this->mapping_model->get_mapping_statistics()
        ];

        $this->load->view('admin/includes/header', $data);
        $this->load->view('admin/mapping_management', $data);
        $this->load->view('admin/includes/footer');
    }

    /**
     * Get mappings with filtering and pagination
     */
    public function get_mappings()
    {
        if (!has_permission('desk_moloni', '', 'view')) {
            $this->output
                ->set_status_header(403)
                ->set_content_type('application/json')
                ->set_output(json_encode(['success' => false, 'message' => _l('access_denied')]));
            return;
        }

        try {
            $filters = [
                'entity_type' => $this->input->get('entity_type'),
                'sync_direction' => $this->input->get('sync_direction'),
                'search' => $this->input->get('search'),
                'last_sync_from' => $this->input->get('last_sync_from'),
                'last_sync_to' => $this->input->get('last_sync_to')
            ];

            $pagination = [
                'limit' => (int) $this->input->get('limit') ?: 50,
                'offset' => (int) $this->input->get('offset') ?: 0
            ];

            $mapping_data = $this->mapping_model->get_filtered_mappings($filters, $pagination);

            // Enrich mappings with entity names
            foreach ($mapping_data['mappings'] as &$mapping) {
                $mapping['perfex_name'] = $this->_get_entity_name('perfex', $mapping['entity_type'], $mapping['perfex_id']);
                $mapping['moloni_name'] = $this->_get_entity_name('moloni', $mapping['entity_type'], $mapping['moloni_id']);
            }

            $this->output
                ->set_content_type('application/json')
                ->set_output(json_encode([
                    'success' => true,
                    'data' => [
                        'total' => $mapping_data['total'],
                        'mappings' => $mapping_data['mappings'],
                        'pagination' => [
                            'current_page' => floor($pagination['offset'] / $pagination['limit']) + 1,
                            'per_page' => $pagination['limit'],
                            'total_items' => $mapping_data['total'],
                            'total_pages' => ceil($mapping_data['total'] / $pagination['limit'])
                        ]
                    ]
                ]));

        } catch (Exception $e) {
            log_message('error', 'Desk-Moloni get mappings error: ' . $e->getMessage());
            
            $this->output
                ->set_status_header(500)
                ->set_content_type('application/json')
                ->set_output(json_encode([
                    'success' => false,
                    'message' => $e->getMessage()
                ]));
        }
    }

    /**
     * Create manual mapping
     */
    public function create_mapping()
    {
        if (!has_permission('desk_moloni', '', 'create')) {
            $this->output
                ->set_status_header(403)
                ->set_content_type('application/json')
                ->set_output(json_encode(['success' => false, 'message' => _l('access_denied')]));
            return;
        }

        try {
            $mapping_data = [
                'entity_type' => $this->input->post('entity_type'),
                'perfex_id' => (int) $this->input->post('perfex_id'),
                'moloni_id' => (int) $this->input->post('moloni_id'),
                'sync_direction' => $this->input->post('sync_direction') ?: 'bidirectional'
            ];

            // Validate required fields
            if (empty($mapping_data['entity_type']) || empty($mapping_data['perfex_id']) || empty($mapping_data['moloni_id'])) {
                throw new Exception(_l('desk_moloni_mapping_missing_required_fields'));
            }

            // Validate entity type
            if (!in_array($mapping_data['entity_type'], ['client', 'product', 'invoice', 'estimate', 'credit_note'])) {
                throw new Exception(_l('desk_moloni_invalid_entity_type'));
            }

            // Validate sync direction
            if (!in_array($mapping_data['sync_direction'], ['perfex_to_moloni', 'moloni_to_perfex', 'bidirectional'])) {
                throw new Exception(_l('desk_moloni_invalid_sync_direction'));
            }

            // Validate entities exist
            if (!$this->_validate_perfex_entity($mapping_data['entity_type'], $mapping_data['perfex_id'])) {
                throw new Exception(_l('desk_moloni_perfex_entity_not_found'));
            }

            if (!$this->_validate_moloni_entity($mapping_data['entity_type'], $mapping_data['moloni_id'])) {
                throw new Exception(_l('desk_moloni_moloni_entity_not_found'));
            }

            // Check for existing mappings
            if ($this->mapping_model->mapping_exists($mapping_data['entity_type'], $mapping_data['perfex_id'], 'perfex')) {
                throw new Exception(_l('desk_moloni_perfex_mapping_exists'));
            }

            if ($this->mapping_model->mapping_exists($mapping_data['entity_type'], $mapping_data['moloni_id'], 'moloni')) {
                throw new Exception(_l('desk_moloni_moloni_mapping_exists'));
            }

            $mapping_id = $this->mapping_model->create_mapping($mapping_data);

            $this->output
                ->set_content_type('application/json')
                ->set_output(json_encode([
                    'success' => true,
                    'message' => _l('desk_moloni_mapping_created_successfully'),
                    'data' => ['mapping_id' => $mapping_id]
                ]));

        } catch (Exception $e) {
            log_message('error', 'Desk-Moloni create mapping error: ' . $e->getMessage());
            
            $this->output
                ->set_status_header(400)
                ->set_content_type('application/json')
                ->set_output(json_encode([
                    'success' => false,
                    'message' => $e->getMessage()
                ]));
        }
    }

    /**
     * Update mapping
     */
    public function update_mapping($mapping_id)
    {
        if (!has_permission('desk_moloni', '', 'edit')) {
            $this->output
                ->set_status_header(403)
                ->set_content_type('application/json')
                ->set_output(json_encode(['success' => false, 'message' => _l('access_denied')]));
            return;
        }

        try {
            $mapping_id = (int) $mapping_id;
            
            if (!$mapping_id) {
                throw new Exception(_l('desk_moloni_invalid_mapping_id'));
            }

            $update_data = [];
            
            // Only allow updating sync_direction
            if ($this->input->post('sync_direction') !== null) {
                $sync_direction = $this->input->post('sync_direction');
                if (!in_array($sync_direction, ['perfex_to_moloni', 'moloni_to_perfex', 'bidirectional'])) {
                    throw new Exception(_l('desk_moloni_invalid_sync_direction'));
                }
                $update_data['sync_direction'] = $sync_direction;
            }

            if (empty($update_data)) {
                throw new Exception(_l('desk_moloni_no_update_data'));
            }

            $result = $this->mapping_model->update_mapping($mapping_id, $update_data);

            if (!$result) {
                throw new Exception(_l('desk_moloni_mapping_update_failed'));
            }

            $this->output
                ->set_content_type('application/json')
                ->set_output(json_encode([
                    'success' => true,
                    'message' => _l('desk_moloni_mapping_updated_successfully')
                ]));

        } catch (Exception $e) {
            log_message('error', 'Desk-Moloni update mapping error: ' . $e->getMessage());
            
            $this->output
                ->set_status_header(400)
                ->set_content_type('application/json')
                ->set_output(json_encode([
                    'success' => false,
                    'message' => $e->getMessage()
                ]));
        }
    }

    /**
     * Delete mapping
     */
    public function delete_mapping($mapping_id)
    {
        if (!has_permission('desk_moloni', '', 'delete')) {
            $this->output
                ->set_status_header(403)
                ->set_content_type('application/json')
                ->set_output(json_encode(['success' => false, 'message' => _l('access_denied')]));
            return;
        }

        try {
            $mapping_id = (int) $mapping_id;
            
            if (!$mapping_id) {
                throw new Exception(_l('desk_moloni_invalid_mapping_id'));
            }

            $result = $this->mapping_model->delete_mapping($mapping_id);

            if (!$result) {
                throw new Exception(_l('desk_moloni_mapping_delete_failed'));
            }

            $this->output
                ->set_content_type('application/json')
                ->set_output(json_encode([
                    'success' => true,
                    'message' => _l('desk_moloni_mapping_deleted_successfully')
                ]));

        } catch (Exception $e) {
            log_message('error', 'Desk-Moloni delete mapping error: ' . $e->getMessage());
            
            $this->output
                ->set_status_header(400)
                ->set_content_type('application/json')
                ->set_output(json_encode([
                    'success' => false,
                    'message' => $e->getMessage()
                ]));
        }
    }

    /**
     * Bulk mapping operations
     */
    public function bulk_operation()
    {
        if (!has_permission('desk_moloni', '', 'edit')) {
            $this->output
                ->set_status_header(403)
                ->set_content_type('application/json')
                ->set_output(json_encode(['success' => false, 'message' => _l('access_denied')]));
            return;
        }

        try {
            $operation = $this->input->post('operation');
            $mapping_ids = $this->input->post('mapping_ids');
            
            if (empty($operation) || empty($mapping_ids) || !is_array($mapping_ids)) {
                throw new Exception(_l('desk_moloni_bulk_operation_invalid_params'));
            }

            $results = [];
            $success_count = 0;
            $error_count = 0;

            foreach ($mapping_ids as $mapping_id) {
                try {
                    $mapping_id = (int) $mapping_id;
                    $result = false;

                    switch ($operation) {
                        case 'delete':
                            $result = $this->mapping_model->delete_mapping($mapping_id);
                            break;
                        case 'sync_perfex_to_moloni':
                            $result = $this->mapping_model->update_mapping($mapping_id, ['sync_direction' => 'perfex_to_moloni']);
                            break;
                        case 'sync_moloni_to_perfex':
                            $result = $this->mapping_model->update_mapping($mapping_id, ['sync_direction' => 'moloni_to_perfex']);
                            break;
                        case 'sync_bidirectional':
                            $result = $this->mapping_model->update_mapping($mapping_id, ['sync_direction' => 'bidirectional']);
                            break;
                        default:
                            throw new Exception(_l('desk_moloni_invalid_bulk_operation'));
                    }

                    if ($result) {
                        $success_count++;
                        $results[$mapping_id] = ['success' => true];
                    } else {
                        $error_count++;
                        $results[$mapping_id] = ['success' => false, 'error' => 'Operation failed'];
                    }

                } catch (Exception $e) {
                    $error_count++;
                    $results[$mapping_id] = ['success' => false, 'error' => $e->getMessage()];
                }
            }

            $this->output
                ->set_content_type('application/json')
                ->set_output(json_encode([
                    'success' => $success_count > 0,
                    'message' => sprintf(
                        _l('desk_moloni_bulk_operation_results'),
                        $success_count,
                        $error_count
                    ),
                    'data' => [
                        'success_count' => $success_count,
                        'error_count' => $error_count,
                        'results' => $results
                    ]
                ]));

        } catch (Exception $e) {
            log_message('error', 'Desk-Moloni bulk mapping operation error: ' . $e->getMessage());
            
            $this->output
                ->set_status_header(400)
                ->set_content_type('application/json')
                ->set_output(json_encode([
                    'success' => false,
                    'message' => $e->getMessage()
                ]));
        }
    }

    /**
     * Auto-discover and suggest mappings
     */
    public function auto_discover()
    {
        if (!has_permission('desk_moloni_admin', '', 'create')) {
            $this->output
                ->set_status_header(403)
                ->set_content_type('application/json')
                ->set_output(json_encode(['success' => false, 'message' => _l('access_denied')]));
            return;
        }

        try {
            $entity_type = $this->input->post('entity_type');
            $auto_create = $this->input->post('auto_create') === '1';
            
            if (empty($entity_type)) {
                throw new Exception(_l('desk_moloni_entity_type_required'));
            }

            $this->load->library('desk_moloni/entity_mapping_service');
            $suggestions = $this->entity_mapping_service->discover_mappings($entity_type);

            $created_count = 0;
            if ($auto_create && !empty($suggestions)) {
                foreach ($suggestions as $suggestion) {
                    try {
                        $this->mapping_model->create_mapping([
                            'entity_type' => $entity_type,
                            'perfex_id' => $suggestion['perfex_id'],
                            'moloni_id' => $suggestion['moloni_id'],
                            'sync_direction' => 'bidirectional'
                        ]);
                        $created_count++;
                    } catch (Exception $e) {
                        // Continue with other suggestions if one fails
                        log_message('warning', 'Auto-create mapping failed: ' . $e->getMessage());
                    }
                }
            }

            $this->output
                ->set_content_type('application/json')
                ->set_output(json_encode([
                    'success' => true,
                    'message' => sprintf(
                        _l('desk_moloni_auto_discover_results'),
                        count($suggestions),
                        $created_count
                    ),
                    'data' => [
                        'suggestions' => $suggestions,
                        'created_count' => $created_count
                    ]
                ]));

        } catch (Exception $e) {
            log_message('error', 'Desk-Moloni auto discover error: ' . $e->getMessage());
            
            $this->output
                ->set_status_header(500)
                ->set_content_type('application/json')
                ->set_output(json_encode([
                    'success' => false,
                    'message' => $e->getMessage()
                ]));
        }
    }

    /**
     * Get entity suggestions for mapping creation
     */
    public function get_entity_suggestions()
    {
        if (!has_permission('desk_moloni', '', 'view')) {
            $this->output
                ->set_status_header(403)
                ->set_content_type('application/json')
                ->set_output(json_encode(['success' => false, 'message' => _l('access_denied')]));
            return;
        }

        try {
            $entity_type = $this->input->get('entity_type');
            $system = $this->input->get('system'); // 'perfex' or 'moloni'
            $search = $this->input->get('search');
            $limit = (int) $this->input->get('limit') ?: 20;

            if (empty($entity_type) || empty($system)) {
                throw new Exception(_l('desk_moloni_missing_parameters'));
            }

            $suggestions = [];

            if ($system === 'perfex') {
                $suggestions = $this->_get_perfex_entity_suggestions($entity_type, $search, $limit);
            } else {
                $suggestions = $this->_get_moloni_entity_suggestions($entity_type, $search, $limit);
            }

            $this->output
                ->set_content_type('application/json')
                ->set_output(json_encode([
                    'success' => true,
                    'data' => $suggestions
                ]));

        } catch (Exception $e) {
            log_message('error', 'Desk-Moloni entity suggestions error: ' . $e->getMessage());
            
            $this->output
                ->set_status_header(500)
                ->set_content_type('application/json')
                ->set_output(json_encode([
                    'success' => false,
                    'message' => $e->getMessage()
                ]));
        }
    }

    /**
     * Get entity name for display
     */
    private function _get_entity_name($system, $entity_type, $entity_id)
    {
        try {
            if ($system === 'perfex') {
                return $this->_get_perfex_entity_name($entity_type, $entity_id);
            } else {
                return $this->_get_moloni_entity_name($entity_type, $entity_id);
            }
        } catch (Exception $e) {
            return "ID: $entity_id";
        }
    }

    /**
     * Get Perfex entity name
     */
    private function _get_perfex_entity_name($entity_type, $entity_id)
    {
        switch ($entity_type) {
            case 'client':
                $this->load->model('clients_model');
                $client = $this->clients_model->get($entity_id);
                return $client ? $client->company : "Client #$entity_id";
            
            case 'product':
                $this->load->model('items_model');
                $item = $this->items_model->get($entity_id);
                return $item ? $item->description : "Product #$entity_id";
            
            case 'invoice':
                $this->load->model('invoices_model');
                $invoice = $this->invoices_model->get($entity_id);
                return $invoice ? format_invoice_number($invoice->id) : "Invoice #$entity_id";
            
            case 'estimate':
                $this->load->model('estimates_model');
                $estimate = $this->estimates_model->get($entity_id);
                return $estimate ? format_estimate_number($estimate->id) : "Estimate #$entity_id";
            
            case 'credit_note':
                $this->load->model('credit_notes_model');
                $credit_note = $this->credit_notes_model->get($entity_id);
                return $credit_note ? format_credit_note_number($credit_note->id) : "Credit Note #$entity_id";
            
            default:
                return "Entity #$entity_id";
        }
    }

    /**
     * Get Moloni entity name
     */
    private function _get_moloni_entity_name($entity_type, $entity_id)
    {
        try {
            $this->load->library('desk_moloni/moloni_api_client');
            $entity_data = $this->moloni_api_client->get_entity($entity_type, $entity_id);
            
            switch ($entity_type) {
                case 'client':
                    return $entity_data['name'] ?? "Client #$entity_id";
                case 'product':
                    return $entity_data['name'] ?? "Product #$entity_id";
                case 'invoice':
                    return $entity_data['document_set_name'] . ' ' . $entity_data['number'] ?? "Invoice #$entity_id";
                case 'estimate':
                    return $entity_data['document_set_name'] . ' ' . $entity_data['number'] ?? "Estimate #$entity_id";
                case 'credit_note':
                    return $entity_data['document_set_name'] . ' ' . $entity_data['number'] ?? "Credit Note #$entity_id";
                default:
                    return "Entity #$entity_id";
            }
        } catch (Exception $e) {
            return "Entity #$entity_id";
        }
    }

    /**
     * Validate Perfex entity exists
     */
    private function _validate_perfex_entity($entity_type, $entity_id)
    {
        switch ($entity_type) {
            case 'client':
                $this->load->model('clients_model');
                return $this->clients_model->get($entity_id) !== false;
            case 'product':
                $this->load->model('items_model');
                return $this->items_model->get($entity_id) !== false;
            case 'invoice':
                $this->load->model('invoices_model');
                return $this->invoices_model->get($entity_id) !== false;
            case 'estimate':
                $this->load->model('estimates_model');
                return $this->estimates_model->get($entity_id) !== false;
            case 'credit_note':
                $this->load->model('credit_notes_model');
                return $this->credit_notes_model->get($entity_id) !== false;
            default:
                return false;
        }
    }

    /**
     * Validate Moloni entity exists
     */
    private function _validate_moloni_entity($entity_type, $entity_id)
    {
        try {
            $this->load->library('desk_moloni/moloni_api_client');
            $entity = $this->moloni_api_client->get_entity($entity_type, $entity_id);
            return !empty($entity);
        } catch (Exception $e) {
            return false;
        }
    }

    /**
     * Get Perfex entity suggestions
     */
    private function _get_perfex_entity_suggestions($entity_type, $search = '', $limit = 20)
    {
        // Implementation depends on specific models and search requirements
        // This is a simplified version
        $suggestions = [];
        
        switch ($entity_type) {
            case 'client':
                $this->load->model('clients_model');
                // Get clients with search filter
                $clients = $this->clients_model->get('', ['limit' => $limit]);
                foreach ($clients as $client) {
                    $suggestions[] = [
                        'id' => $client['userid'],
                        'name' => $client['company']
                    ];
                }
                break;
            // Add other entity types as needed
        }

        return $suggestions;
    }

    /**
     * Get Moloni entity suggestions
     */
    private function _get_moloni_entity_suggestions($entity_type, $search = '', $limit = 20)
    {
        try {
            $this->load->library('desk_moloni/moloni_api_client');
            return $this->moloni_api_client->search_entities($entity_type, $search, $limit);
        } catch (Exception $e) {
            return [];
        }
    }
}