<?php
defined('BASEPATH') OR exit('No direct script access allowed');
class Caisse_model extends CI_Model {
    
    public function __construct() {
        parent::__construct();
        $this->load->database();
        $this->load->model('Transaction_model');
        $this->load->model('Fret_model');
    }


    /**
     * Ouvrir session de caisse
     */
    public function ouvrir_session($caissier_id, $montant_ouverture, $decompte_pieces = array()) {
        // Vérifier qu'il n'y a pas déjà une session ouverte
        $this->db->where('caissier_id', $caissier_id);
        $this->db->where('statut', 'OUVERTE');
        $session_ouverte = $this->db->get('sessions_caisse')->row();

        if ($session_ouverte) {
            return array('success' => FALSE, 'error' => 'Une session est déjà ouverte');
        }

        // Générer numéro de session unique
        $numero_session = $this->generer_numero_session($caissier_id);

        // Récupérer montant théorique (fermeture session précédente)
        $this->db->where('caissier_id', $caissier_id);
        $this->db->where('statut', 'FERMEE');
        $this->db->where('DATE(date_fermeture)', date('Y-m-d', strtotime('-1 day')));
        $this->db->order_by('date_fermeture', 'DESC');
        $session_precedente = $this->db->get('sessions_caisse')->row();

        $montant_theorique = $session_precedente ? $session_precedente->montant_fermeture_declare : 0;

        $session_data = array_merge(array(
            'caissier_id' => $caissier_id,
            'numero_session' => $numero_session, // AJOUT DE CETTE LIGNE
            'date_ouverture' => date('Y-m-d H:i:s'),
            'montant_ouverture_declare' => $montant_ouverture,
            'montant_ouverture_theorique' => $montant_theorique,
            'ecart_ouverture' => $montant_ouverture - $montant_theorique,
            'statut' => 'OUVERTE'
        ), $decompte_pieces);

        // Calculer total décompte espèces
        $session_data['total_decomp_especes'] = $this->calculer_total_especes($decompte_pieces);

        $session_id = $this->db->insert('sessions_caisse', $session_data) ? $this->db->insert_id() : FALSE;

        // Enregistrer écart si significatif
        if ($session_id && abs($session_data['ecart_ouverture']) > 500) {
            $this->enregistrer_ecart($session_id, 'OUVERTURE', $session_data['ecart_ouverture'], 
                                $montant_ouverture, $montant_theorique);
        }

        return array('success' => (bool)$session_id, 'session_id' => $session_id);
    }

    /**
     * Générer un numéro de session unique
     */
    private function generer_numero_session($caissier_id) {
        // Format: CAI-{ID_CAISSIER}-{DATE}-{COUNTER}
        // Exemple: CAI-001-20250926-001
        
        $date_today = date('Ymd');
        $caissier_formatted = str_pad($caissier_id, 3, '0', STR_PAD_LEFT);
        
        $counter = 1;
        $numero_session = '';
        
        // Boucle pour s'assurer de l'unicité
        do {
            $counter_formatted = str_pad($counter, 3, '0', STR_PAD_LEFT);
            $numero_session = "CAI-{$caissier_formatted}-{$date_today}-{$counter_formatted}";
            
            // Vérifier si ce numéro existe déjà
            $this->db->where('numero_session', $numero_session);
            $exists = $this->db->count_all_results('sessions_caisse') > 0;
            
            $counter++;
        } while ($exists && $counter <= 999); // Limite de sécurité
        
        return $numero_session;
    }

    /**
     * Calculer total espèces selon décompte
     */
    private function calculer_total_especes($decompte_pieces) {
        $denominations = array(
            'pieces_1fc' => 1, 'pieces_5fc' => 5, 'pieces_10fc' => 10, 'pieces_25fc' => 25,
            'pieces_50fc' => 50, 'pieces_100fc' => 100, 'pieces_250fc' => 250,
            'billets_500fc' => 500, 'billets_1000fc' => 1000, 'billets_2000fc' => 2000,
            'billets_5000fc' => 5000, 'billets_10000fc' => 10000
        );

        $total = 0;
        foreach ($denominations as $piece => $valeur) {
            if (isset($decompte_pieces[$piece])) {
                $total += $decompte_pieces[$piece] * $valeur;
            }
        }

        return $total;
    }

    /**
     * Obtenir session ouverte d'un caissier
     */
    public function get_session_ouverte($caissier_id) {
        $this->db->where('caissier_id', $caissier_id);
        $this->db->where('statut', 'OUVERTE');
        return $this->db->get('sessions_caisse')->row();
    }

   
    /**
     * Confirmer paiement réservation
     */

    public function confirmer_paiement_reservation($billet_id, $mode_paiement, $numero_transaction, $caissier_id, $montant_recu = NULL) {
        $this->db->trans_start();

        try {
            // Vérifier session ouverte
            $session = $this->get_session_ouverte($caissier_id);
            if (!$session) {
                throw new Exception('Aucune session de caisse ouverte');
            }

            // Confirmer paiement du billet
            $this->load->model('Billet_model');
            if (!$this->Billet_model->confirmer_paiement($billet_id, $caissier_id)) {
                throw new Exception('Erreur lors de la confirmation du billet');
            }

            // CORRECTION : Récupérer montant du billet directement
            $billet = $this->db->get_where('billets', array('id' => $billet_id))->row();
            $montant = $billet->tarif_total; // ← UTILISER billets.tarif_total

            // Générer numéro de transaction si vide ou non fourni
            if (empty($numero_transaction)) {
                $numero_transaction = $this->generer_numero_transaction($session->id, $mode_paiement);
            }

            // Enregistrer transaction
            $transaction_data = array(
                'session_caisse_id' => $session->id,
                'numero_transaction' => $numero_transaction,
                'type_transaction' => 'PAIEMENT',
                'reference' => $billet->numero_billet,
                'montant' => $montant, // ← Maintenant utilise billets.tarif_total
                'mode_paiement' => $mode_paiement,
                'montant_recu' => $montant_recu,
                'monnaie_rendue' => ($mode_paiement === 'ESPECES' && $montant_recu) ? $montant_recu - $montant : 0,
                'statut_transaction' => 'VALIDEE',
                'date_validation' => date('Y-m-d H:i:s'),
                'created_by' => $caissier_id
            );

            $this->Transaction_model->insert_transaction($transaction_data);

            $this->db->trans_complete();

            if ($this->db->trans_status() === FALSE) {
                throw new Exception('Erreur lors de l\'enregistrement');
            }

            return array('success' => TRUE, 'billet_id' => $billet_id);

        } catch (Exception $e) {
            $this->db->trans_rollback();
            return array('success' => FALSE, 'error' => $e->getMessage());
        }
    }


    

   

    /**
     * Générer un numéro de transaction unique
     */
    private function generer_numero_transaction($session_id, $mode_paiement) {
        // Format: TXN-{SESSION_ID}-{MODE}-{TIMESTAMP}-{COUNTER}
        // Exemple: TXN-001-ESP-20250926211249-001
        
        $session_formatted = str_pad($session_id, 3, '0', STR_PAD_LEFT);
        $mode_code = substr($mode_paiement, 0, 3); // ESP, CAR, VIR, CHE, VOU
        $timestamp = date('YmdHis');
        
        $counter = 1;
        $numero_transaction = '';
        
        // Boucle pour s'assurer de l'unicité
        do {
            $counter_formatted = str_pad($counter, 3, '0', STR_PAD_LEFT);
            $numero_transaction = "TXN-{$session_formatted}-{$mode_code}-{$timestamp}-{$counter_formatted}";
            
            // Vérifier si ce numéro existe déjà
            $this->db->where('numero_transaction', $numero_transaction);
            $exists = $this->db->count_all_results('transactions') > 0;
            
            $counter++;
        } while ($exists && $counter <= 999); // Limite de sécurité
        
        return $numero_transaction;
    }

    /**
     * Fermer session de caisse
     */



    /**
     * Fermer session de caisse - VERSION CORRIGÉE
     */
    public function fermer_session($caissier_id, $montant_fermeture, $decompte_pieces = array()) {
        $session = $this->get_session_ouverte($caissier_id);
        if (!$session) {
            return array('success' => FALSE, 'error' => 'Aucune session ouverte');
        }

        // CALCUL CORRECT DU MONTANT THÉORIQUE
        // Récupérer directement les totaux depuis la table transactions
        // CORRECTION: Inclure les transactions FRET (montant positif = encaissement, négatif = remboursement)
        $this->db->select('
            SUM(CASE 
                WHEN type_transaction = "PAIEMENT" THEN montant 
                WHEN type_transaction = "FRET" AND montant > 0 THEN montant 
                ELSE 0 
            END) as total_encaissements,
            SUM(CASE 
                WHEN type_transaction = "REMBOURSEMENT" THEN montant 
                WHEN type_transaction = "FRET" AND montant < 0 THEN ABS(montant) 
                ELSE 0 
            END) as total_remboursements
        ');
        $this->db->where('session_caisse_id', $session->id);
        $this->db->where('statut_transaction', 'VALIDEE');
        $totaux = $this->db->get('transactions')->row();

        $total_encaissements = $totaux->total_encaissements ?: 0;
        $total_remboursements = $totaux->total_remboursements ?: 0;

        // Calcul montant théorique correct
        $montant_theorique = $session->montant_ouverture_declare + $total_encaissements - $total_remboursements;
        
        $ecart_fermeture = $montant_fermeture - $montant_theorique;

        // Mettre à jour session
        $update_data = array_merge(array(
            'date_fermeture' => date('Y-m-d H:i:s'),
            'montant_fermeture_declare' => $montant_fermeture,
            'montant_fermeture_theorique' => $montant_theorique,
            'ecart_fermeture' => $ecart_fermeture,
            'total_encaissements' => $total_encaissements,
            'total_remboursements' => $total_remboursements,
            'statut' => 'FERMEE'
        ), $decompte_pieces);

        $update_data['total_decomp_especes'] = $this->calculer_total_especes($decompte_pieces);

        $this->db->where('id', $session->id);
        $success = $this->db->update('sessions_caisse', $update_data);

        // Enregistrer écart si significatif
        if ($success && abs($ecart_fermeture) > 500) {
            $this->enregistrer_ecart($session->id, 'FERMETURE', $ecart_fermeture, 
                                $montant_fermeture, $montant_theorique);
        }

        return array(
            'success' => (bool)$success,
            'session_id' => $session->id,
            'ecart' => $ecart_fermeture,
            'montant_theorique' => $montant_theorique,
            'details' => array(
                'ouverture' => $session->montant_ouverture_declare,
                'encaissements' => $total_encaissements,
                'remboursements' => $total_remboursements
            )
        );
    }

    /**
     * Méthode de vérification pour debugger
     */
    public function debug_session_totaux($session_id) {
        // Vérifier les transactions de la session
        $this->db->select('*');
        $this->db->where('session_caisse_id', $session_id);
        $transactions = $this->db->get('transactions')->result();
        
        echo "<h3>Debug Session ID: $session_id</h3>";
        echo "<h4>Transactions:</h4>";
        foreach($transactions as $trans) {
            echo "- ID: {$trans->id}, Type: {$trans->type_transaction}, Montant: {$trans->montant}, Statut: {$trans->statut_transaction}<br>";
        }
        
        // Calculer totaux - CORRECTION: Inclure les transactions FRET
        $this->db->select('
            SUM(CASE 
                WHEN type_transaction = "PAIEMENT" AND statut_transaction = "VALIDEE" THEN montant 
                WHEN type_transaction = "FRET" AND statut_transaction = "VALIDEE" AND montant > 0 THEN montant 
                ELSE 0 
            END) as total_encaissements,
            SUM(CASE 
                WHEN type_transaction = "REMBOURSEMENT" AND statut_transaction = "VALIDEE" THEN montant 
                WHEN type_transaction = "FRET" AND statut_transaction = "VALIDEE" AND montant < 0 THEN ABS(montant) 
                ELSE 0 
            END) as total_remboursements
        ');
        $this->db->where('session_caisse_id', $session_id);
        $totaux = $this->db->get('transactions')->row();
        
        echo "<h4>Totaux calculés:</h4>";
        echo "- Encaissements: " . ($totaux->total_encaissements ?: 0) . " FC<br>";
        echo "- Remboursements: " . ($totaux->total_remboursements ?: 0) . " FC<br>";
    }
    

    /**
     * Enregistrer un écart de caisse
     */
    private function enregistrer_ecart($session_id, $type_ecart, $montant_ecart, $montant_declare, $montant_theorique) {
        $ecart_data = array(
            'session_caisse_id' => $session_id,
            'type_ecart' => $type_ecart,
            'montant_ecart' => $montant_ecart,
            'montant_declare' => $montant_declare,
            'montant_theorique' => $montant_theorique,
            'statut_enquete' => 'OUVERTE'
        );

        $this->db->insert('ecarts_caisse', $ecart_data);
    }

    /**
     * Obtenir rapport de session
     */
    public function get_rapport_session($session_id) {
        $this->db->select('sessions_caisse.*, utilisateurs.nom as caissier_nom, utilisateurs.prenom as caissier_prenom');
        $this->db->from('sessions_caisse');
        $this->db->join('utilisateurs', 'sessions_caisse.caissier_id = utilisateurs.id');
        $this->db->where('sessions_caisse.id', $session_id);
        $session = $this->db->get()->row();

        if ($session) {
            // Ajouter transactions
            $session->transactions = $this->Transaction_model->get_transactions_session($session_id);

            // Ajouter écarts
            $this->db->where('session_caisse_id', $session_id);
            $session->ecarts = $this->db->get('ecarts_caisse')->result();
        }

        return $session;
    }





    // Ajoutez ces méthodes à votre classe Caisse_model

    /**
     * Récupérer sessions avec filtres
     */
    public function get_sessions_with_filters($filters, $limit = true) {
        $this->db->select('
            sc.*,
            u.nom as caissier_nom,
            u.prenom as caissier_prenom,
            u.agence
        ');
        $this->db->from('sessions_caisse sc');
        $this->db->join('utilisateurs u', 'sc.caissier_id = u.id', 'left');
        
        // Appliquer les filtres
        if (!empty($filters['date_debut'])) {
            $this->db->where('DATE(sc.date_ouverture) >=', $filters['date_debut']);
        }
        
        if (!empty($filters['date_fin'])) {
            $this->db->where('DATE(sc.date_ouverture) <=', $filters['date_fin']);
        }
        
        if (!empty($filters['caissier_id'])) {
            $this->db->where('sc.caissier_id', $filters['caissier_id']);
        }
        
        if (!empty($filters['statut'])) {
            $this->db->where('sc.statut', $filters['statut']);
        }
        
        $this->db->order_by('sc.date_ouverture', 'DESC');
        
        if ($limit) {
            $this->db->limit(50); // Limiter à 50 sessions pour la vue
        }
        
        return $this->db->get()->result();
    }

    /**
     * Récupérer tous les caissiers
     */
    public function get_all_caissiers() {
        $this->db->select('u.id, u.nom, u.prenom');
        $this->db->from('utilisateurs u');
        $this->db->join('roles r', 'u.role_id = r.id');
        $this->db->where_in('r.nom', array('admin', 'caissier'));
        $this->db->where('u.actif', 1);
        $this->db->order_by('u.nom');
        
        return $this->db->get()->result();
    }

    /**
     * Statistiques des sessions
     */
    public function get_sessions_stats($filters) {
        $stats = array();
        
        // Sessions aujourd'hui
        $this->db->where('DATE(date_ouverture)', date('Y-m-d'));
        $stats['sessions_today'] = $this->db->count_all_results('sessions_caisse');
        
        // Encaissements du jour
        $this->db->select('SUM(total_encaissements) as total');
        $this->db->where('DATE(date_ouverture)', date('Y-m-d'));
        $this->db->where('statut !=', 'OUVERTE');
        $result = $this->db->get('sessions_caisse')->row();
        $stats['total_day'] = $result->total ?: 0;
        
        // Écarts à traiter
        $this->db->where('statut_enquete', 'OUVERTE');
        $stats['ecarts_count'] = $this->db->count_all_results('ecarts_caisse');
        
        return $stats;
    }

    /**
     * Récupérer une session avec tous ses détails
     */
    public function get_session_complete($session_id) {
        // Session principale
        $this->db->select('
            sc.*,
            u.nom as caissier_nom,
            u.prenom as caissier_prenom,
            u.agence
        ');
        $this->db->from('sessions_caisse sc');
        $this->db->join('utilisateurs u', 'sc.caissier_id = u.id', 'left');
        $this->db->where('sc.id', $session_id);
        $session = $this->db->get()->row();
        
        if (!$session) {
            return null;
        }
        
        // Transactions
        $this->db->select('*');
        $this->db->where('session_caisse_id', $session_id);
        $this->db->order_by('created_at', 'ASC');
        $session->transactions = $this->db->get('transactions')->result();
        
        // Écarts
        $this->db->where('session_caisse_id', $session_id);
        $session->ecarts = $this->db->get('ecarts_caisse')->result();
        
        return $session;
    }

    /**
     * Calculer les totaux en temps réel pour une session
     * CORRECTION: Inclure les transactions FRET
     */
    public function calculer_totaux_session($session_id) {
        $this->db->select('
            SUM(CASE 
                WHEN type_transaction = "PAIEMENT" AND statut_transaction = "VALIDEE" THEN montant 
                WHEN type_transaction = "FRET" AND statut_transaction = "VALIDEE" AND montant > 0 THEN montant 
                ELSE 0 
            END) as total_encaissements,
            SUM(CASE 
                WHEN type_transaction = "REMBOURSEMENT" AND statut_transaction = "VALIDEE" THEN montant 
                WHEN type_transaction = "FRET" AND statut_transaction = "VALIDEE" AND montant < 0 THEN ABS(montant) 
                ELSE 0 
            END) as total_remboursements,
            SUM(CASE WHEN type_transaction = "PAIEMENT" AND statut_transaction = "VALIDEE" THEN montant ELSE 0 END) as total_passagers,
            SUM(CASE WHEN type_transaction = "FRET" AND statut_transaction = "VALIDEE" AND montant > 0 THEN montant ELSE 0 END) as total_fret,
            COUNT(CASE WHEN statut_transaction = "VALIDEE" THEN 1 END) as nb_transactions
        ');
        $this->db->where('session_caisse_id', $session_id);
        
        return $this->db->get('transactions')->row();
    }

    /**
     * Vérifier cohérence des montants d'une session
     */
    public function verifier_coherence_session($session_id) {
        $session = $this->db->get_where('sessions_caisse', array('id' => $session_id))->row();
        $totaux = $this->calculer_totaux_session($session_id);
        
        if (!$session || !$totaux) {
            return array('coherent' => false, 'erreur' => 'Session ou transactions introuvables');
        }
        
        $montant_theorique_calcule = $session->montant_ouverture_declare + 
                                    ($totaux->total_encaissements ?: 0) - 
                                    ($totaux->total_remboursements ?: 0);
        
        $coherence = array(
            'coherent' => abs($montant_theorique_calcule - ($session->montant_fermeture_theorique ?: 0)) < 1,
            'montant_theorique_calcule' => $montant_theorique_calcule,
            'montant_theorique_enregistre' => $session->montant_fermeture_theorique,
            'difference' => $montant_theorique_calcule - ($session->montant_fermeture_theorique ?: 0),
            'totaux_transactions' => $totaux
        );
        
        return $coherence;
    }

    /**
     * Corriger les totaux d'une session si nécessaire
     */
    public function corriger_totaux_session($session_id) {
        $totaux = $this->calculer_totaux_session($session_id);
        $session = $this->db->get_where('sessions_caisse', array('id' => $session_id))->row();
        
        if (!$session || !$totaux) {
            return false;
        }
        
        $montant_theorique_correct = $session->montant_ouverture_declare + 
                                    ($totaux->total_encaissements ?: 0) - 
                                    ($totaux->total_remboursements ?: 0);
        
        $ecart_correct = ($session->montant_fermeture_declare ?: 0) - $montant_theorique_correct;
        
        $update_data = array(
            'total_encaissements' => $totaux->total_encaissements ?: 0,
            'total_remboursements' => $totaux->total_remboursements ?: 0,
            'montant_fermeture_theorique' => $montant_theorique_correct,
            'ecart_fermeture' => $ecart_correct,
            'updated_at' => date('Y-m-d H:i:s')
        );
        
        $this->db->where('id', $session_id);
        return $this->db->update('sessions_caisse', $update_data);
    }

    /**
     * Générer rapport quotidien des sessions
     */
    public function generer_rapport_quotidien($date, $agence = null) {
        $this->db->select('
            COUNT(*) as nombre_sessions,
            SUM(total_encaissements) as total_encaissements,
            SUM(total_remboursements) as total_remboursements,
            SUM(total_encaissements - total_remboursements) as solde_net,
            COUNT(CASE WHEN ABS(ecart_fermeture) > 500 THEN 1 END) as sessions_avec_ecart
        ');
        
        $this->db->where('DATE(date_ouverture)', $date);
        $this->db->where('statut !=', 'OUVERTE');
        
        if ($agence) {
            $this->db->join('utilisateurs u', 'sessions_caisse.caissier_id = u.id');
            $this->db->where('u.agence', $agence);
        }
        
        return $this->db->get('sessions_caisse')->row();
    }

    /**
     * Obtenir les sessions avec écarts significatifs
     */
    public function get_sessions_avec_ecarts($seuil = 1000, $limite = 10) {
        $this->db->select('
            sc.*,
            u.nom as caissier_nom,
            u.prenom as caissier_prenom,
            ec.statut_enquete
        ');
        $this->db->from('sessions_caisse sc');
        $this->db->join('utilisateurs u', 'sc.caissier_id = u.id');
        $this->db->join('ecarts_caisse ec', 'sc.id = ec.session_caisse_id', 'left');
        $this->db->where('ABS(sc.ecart_fermeture) >=', $seuil);
        $this->db->order_by('sc.date_fermeture', 'DESC');
        $this->db->limit($limite);
        
        return $this->db->get()->result();
    }




    /**
     * Traiter un remboursement
     */
    public function traiter_remboursement($billet_id, $mode_paiement, $caissier_id) {
        $this->db->trans_start();
        
        try {
            $session = $this->get_session_ouverte($caissier_id);
            if (!$session) {
                throw new Exception('Aucune session de caisse ouverte');
            }
            
            // Récupérer le billet de remboursement
            $billet = $this->db->get_where('billets', array('id' => $billet_id))->row();
            if (!$billet || $billet->type_billet !== 'REMBOURSEMENT') {
                throw new Exception('Billet de remboursement invalide');
            }
            

            // NOUVELLE VÉRIFICATION: Vérifier si le billet n'est pas déjà payé
            if ($billet->statut_billet !== 'EMIS') {
                throw new Exception('Ce remboursement a déjà été traité');
            }
            
            // NOUVELLE VÉRIFICATION: Vérifier qu'il n'y a pas déjà une transaction pour ce billet
            $this->db->where('reference', $billet->numero_billet);
            $this->db->where('type_transaction', 'REMBOURSEMENT');
            $this->db->where('statut_transaction', 'VALIDEE');
            $transaction_existante = $this->db->get('transactions')->row();
            
            if ($transaction_existante) {
                throw new Exception('Une transaction de remboursement existe déjà pour ce billet');
            }
            // Marquer le billet comme payé (remboursé)
            $this->load->model('Billet_model');
            $this->Billet_model->confirmer_paiement($billet_id, $caissier_id);
            
            // Enregistrer la transaction de remboursement
            $transaction_data = array(
                'session_caisse_id' => $session->id,
                'numero_transaction' => $this->generer_numero_transaction($session->id, $mode_paiement),
                'type_transaction' => 'REMBOURSEMENT',
                'reference' => $billet->numero_billet,
                'montant' => $billet->tarif_total,
                'mode_paiement' => $mode_paiement,
                'statut_transaction' => 'VALIDEE',
                'date_validation' => date('Y-m-d H:i:s'),
                'created_by' => $caissier_id
            );
            
            $this->Transaction_model->insert_transaction($transaction_data);
            
            $this->db->trans_complete();
            return array('success' => TRUE);
            
        } catch (Exception $e) {
            $this->db->trans_rollback();
            return array('success' => FALSE, 'error' => $e->getMessage());
        }
    }














        /**
             * Confirmer paiement d'une expédition fret
             * 
             * @param int $expedition_id ID de l'expédition
             * @param string $mode_paiement Mode de paiement (ESPECES, CARTE, VIREMENT, CHEQUE, VOUCHER)
             * @param string $numero_transaction Référence externe (pour mobile money)
             * @param int $caissier_id ID du caissier
             * @param float $montant_recu Montant reçu du client (optionnel)
             * @return array
             */
            public function confirmer_paiement_fret($expedition_id, $mode_paiement, $numero_transaction, $caissier_id, $montant_recu = NULL) {
                $this->db->trans_start();
                
                try {
                    // Vérifier session ouverte
                    $session = $this->get_session_ouverte($caissier_id);
                    if (!$session) {
                        throw new Exception('Aucune session de caisse ouverte');
                    }
                    
                    // Charger le modèle fret
                    $this->load->model('Fret_model');
                    
                    // Récupérer l'expédition
                    $expedition = $this->db->get_where('expeditions_fret_new', array('id' => $expedition_id))->row();
                    if (!$expedition) {
                        throw new Exception('Expédition introuvable');
                    }
                    
                    // Vérifier statut ENREGISTRE + EN_ATTENTE
                    if ($expedition->statut !== 'ENREGISTRE' || $expedition->statut_paiement !== 'EN_ATTENTE') {
                        throw new Exception('Cette expédition n\'est pas en attente de paiement');
                    }
                    
                    $montant = floatval($expedition->tarif_total);
                    
                    // Confirmer le paiement dans le modèle fret
                    $result = $this->Fret_model->confirmer_paiement(
                        $expedition_id, 
                        $caissier_id, 
                        $session->id, 
                        $mode_paiement, 
                        $numero_transaction
                    );
                    
                    if (!$result['success']) {
                        throw new Exception($result['error']);
                    }
                    
                    $this->db->trans_complete();
                    
                    if ($this->db->trans_status() === FALSE) {
                        throw new Exception('Erreur lors de la confirmation');
                    }

                    // Calculer la monnaie à rendre (convertir montant_recu en float)
                    $monnaie = 0;
                    if ($montant_recu !== NULL && $montant_recu !== '') {
                        $montant_recu_float = floatval(str_replace([' ', ','], ['', '.'], $montant_recu));
                        $monnaie = $montant_recu_float - $montant;
                    }
                    
                    return array(
                        'success' => TRUE,
                        'montant' => $montant,
                        'monnaie' => $monnaie
                        //'monnaie' => ($montant_recu !== NULL) ? ($montant_recu - $montant) : 0
                    );
                    
                } catch (Exception $e) {
                    $this->db->trans_rollback();
                    return array('success' => FALSE, 'error' => $e->getMessage());
                }
            }

            /**
             * Traiter un remboursement fret
             * 
             * @param int $expedition_id
             * @param string $mode_paiement
             * @param int $caissier_id
             * @param string $motif
             * @return array
             */
            public function traiter_remboursement_fret($expedition_id, $mode_paiement, $caissier_id, $motif = '') {
                $this->db->trans_start();
                
                try {
                    $session = $this->get_session_ouverte($caissier_id);
                    if (!$session) {
                        throw new Exception('Aucune session de caisse ouverte');
                    }
                    
                    // Récupérer l'expédition
                    $expedition = $this->db->get_where('expeditions_fret_new', array('id' => $expedition_id))->row();
                    if (!$expedition) {
                        throw new Exception('Expédition introuvable');
                    }
                    
                    if ($expedition->statut_paiement !== 'PAYE') {
                        throw new Exception('Cette expédition n\'est pas payée');
                    }
                    
                    // Vérifier qu'il n'y a pas déjà un remboursement
                    $this->db->where('expedition_id', $expedition_id);
                    $this->db->where('type_transaction', 'FRET');
                    $this->db->where('montant <', 0); // Remboursement = montant négatif
                    $this->db->where('statut_transaction', 'VALIDEE');
                    $remboursement_existant = $this->db->get('transactions')->row();
                    
                    if ($remboursement_existant) {
                        throw new Exception('Un remboursement a déjà été effectué pour cette expédition');
                    }
                    
                    $montant = floatval($expedition->tarif_total);
                    
                    // Mettre à jour l'expédition
                    $this->db->update('expeditions_fret_new', array(
                        'statut' => 'REMBOURSE',
                        'statut_paiement' => 'REMBOURSE',
                        'date_remboursement' => date('Y-m-d H:i:s'),
                        'caissier_remboursement' => $caissier_id,
                        'motif_remboursement' => $motif
                    ), array('id' => $expedition_id));
                    
                    // Enregistrer la transaction de remboursement (montant négatif)
                    $transaction_data = array(
                        'session_caisse_id' => $session->id,
                        'numero_transaction' => $this->generer_numero_transaction($session->id, $mode_paiement),
                        'type_transaction' => 'FRET', // Utilise le type FRET existant
                        'expedition_id' => $expedition_id,
                        'reference' => $expedition->numero_expedition,
                        'description' => 'Remboursement fret ' . $expedition->numero_expedition . ($motif ? ' - ' . $motif : ''),
                        'montant' => -$montant, // Montant négatif pour remboursement
                        'mode_paiement' => $mode_paiement,
                        'statut_transaction' => 'VALIDEE',
                        'date_validation' => date('Y-m-d H:i:s'),
                        'created_by' => $caissier_id
                    );
                    
                    $this->Transaction_model->insert_transaction($transaction_data);
                    
                    $this->db->trans_complete();
                    
                    if ($this->db->trans_status() === FALSE) {
                        throw new Exception('Erreur lors du remboursement');
                    }
                    
                    return array('success' => TRUE, 'montant' => $montant);
                    
                } catch (Exception $e) {
                    $this->db->trans_rollback();
                    return array('success' => FALSE, 'error' => $e->getMessage());
                }
            }





        /**
         * Créer transaction de modification
         * Utilise la structure existante avec reference = numero_billet
         */
        public function creer_transaction_modification($numero_billet, $montant, $agent_id) {
            // La transaction est créée EN_ATTENTE
            // Elle sera validée quand le caissier encaisse
            $transaction_data = array(
                'numero_transaction' => 'MOD-' . date('YmdHis') . '-' . rand(100, 999),
                'type_transaction' => 'MODIFICATION',
                'reference' => $numero_billet,
                'montant' => $montant,
                'statut_transaction' => 'EN_ATTENTE',
                'description' => 'Frais de modification - Billet ' . $numero_billet,
                'created_by' => $agent_id,
                'created_at' => date('Y-m-d H:i:s')
            );
            
            $this->db->insert('transactions', $transaction_data);
            return $this->db->insert_id();
        }


        







        /**
     * Confirmer paiement frais de modification
     * Similaire à confirmer_paiement_reservation mais pour les frais de modification
     */
    public function confirmer_paiement_modification($billet_id, $mode_paiement, $numero_transaction, $caissier_id, $montant_recu = NULL) {
        $this->db->trans_start();

        try {
            // Vérifier session ouverte
            $session = $this->get_session_ouverte($caissier_id);
            if (!$session) {
                throw new Exception('Aucune session de caisse ouverte');
            }

            // Récupérer le billet
            $billet = $this->db->get_where('billets', array('id' => $billet_id))->row();
            if (!$billet) {
                throw new Exception('Billet introuvable');
            }
            
            // Vérifier que c'est bien une modification en attente
            if ($billet->statut_billet !== 'EMIS' || empty($billet->frais_modification)) {
                throw new Exception('Ce billet n\'a pas de frais de modification en attente');
            }
            
            $montant = $billet->frais_modification;

            // Passer le billet à PAYE et remettre frais_modification à 0
            $this->db->where('id', $billet_id);
            $this->db->update('billets', array(
                'statut_billet' => 'PAYE',
                'frais_modification' => 0,
                'date_paiement' => date('Y-m-d H:i:s'),
                'caissier_paiement' => $caissier_id
            ));

            // Générer numéro de transaction si vide
            if (empty($numero_transaction)) {
                $numero_transaction = $this->generer_numero_transaction($session->id, $mode_paiement);
            }

            // Enregistrer transaction
            $transaction_data = array(
                'session_caisse_id' => $session->id,
                'numero_transaction' => $numero_transaction,
                'type_transaction' => 'MODIFICATION',
                'reference' => $billet->numero_billet,
                'montant' => $montant,
                'mode_paiement' => $mode_paiement,
                'montant_recu' => $montant_recu,
                'monnaie_rendue' => ($mode_paiement === 'ESPECES' && $montant_recu) ? $montant_recu - $montant : 0,
                'statut_transaction' => 'VALIDEE',
                'date_validation' => date('Y-m-d H:i:s'),
                'created_by' => $caissier_id
            );

            $this->Transaction_model->insert_transaction($transaction_data);

            $this->db->trans_complete();

            if ($this->db->trans_status() === FALSE) {
                throw new Exception('Erreur lors de l\'enregistrement');
            }

            return array('success' => TRUE, 'billet_id' => $billet_id, 'montant' => $montant);

        } catch (Exception $e) {
            $this->db->trans_rollback();
            return array('success' => FALSE, 'error' => $e->getMessage());
        }
    }


    /**
     * Obtenir billets avec frais de modification en attente
     */
    public function get_billets_modification_en_attente() {
        $this->db->select('
            billets.*,
            reservations.nom, reservations.prenom, reservations.telephone,
            voyages.numero_voyage, voyages.date_voyage, voyages.port_depart, voyages.port_arrivee
        ');
        $this->db->from('billets');
        $this->db->join('reservations', 'billets.code_reservation = reservations.code_reservation');
        $this->db->join('voyages', 'billets.voyage_id = voyages.id');
        $this->db->where('billets.statut_billet', 'EMIS');
        $this->db->where('billets.frais_modification >', 0);
        $this->db->order_by('billets.date_modification', 'ASC');
        
        return $this->db->get()->result();
    }









}

?>