<?php
namespace App\Models;

use CodeIgniter\Model;

class Avance extends Model {
    protected $table = 'avances';
    protected $primaryKey = 'avance_id';

    protected $allowedFields = [
        'avance_amount', 'avance_date','user_id',
        'customer_name', 'customer_address', 'customer_phone', 'customer_cin',
        'gross_amount','amount_due','product_id','is_order','active','store_id',
        'type_avance','type_payment', 'deadline','commentaire','product_name' 
    ]; 

    public function createAvance(array $data) {
        try {
            if (empty($data['avance_date'])) {
                $data['avance_date'] = date('Y-m-d');
            }

            if (!empty($data['type'])) {
                if (strtolower($data['type']) === 'avance sur terre') {
                    $data['deadline'] = date('Y-m-d', strtotime($data['avance_date'] . ' +15 days'));
                } elseif (strtolower($data['type']) === 'avance sur mer') {
                    $data['deadline'] = date('Y-m-d', strtotime($data['avance_date'] . ' +2 months'));
                }
            }

            return $this->insert($data);
        } catch (\Exception $e) {
            log_message('error', 'Erreur lors de l\'ajout de l\'avance : ' . $e->getMessage());
            return false;
        }  
    }

    public function updateAvance(int $id, array $data) {
        if ($id <= 0) {
            log_message('error', 'ID invalide pour la mise à jour du recouvrement : ' . $id);
            return false;
        }
        try {
            if (!empty($data['type']) && !empty($data['avance_date'])) {
                if (strtolower($data['type']) === 'avance sur terre') {
                    $data['deadline'] = date('Y-m-d', strtotime($data['avance_date'] . ' +15 days'));
                } elseif (strtolower($data['type']) === 'avance sur mer') {
                    $data['deadline'] = date('Y-m-d', strtotime($data['avance_date'] . ' +2 months'));
                }
            }
            return $this->update($id, $data);
        } catch (\Exception $e) {
            log_message('error', 'Erreur lors de la mise à jour de l\'avance : ' . $e->getMessage());
            return false; 
        }
    }

    public function getAllAvanceData(int $id=null) {
        $session = session();
        $users =  $session->get('user');
        $isAdmin = in_array($users['group_name'], ['Conseil', 'Direction']);
        if($isAdmin) {
            if($id){
                try {
                    return $this->where('user_id',$id)
                        ->where('is_order',0)
                        ->where('active',1)
                        ->orderBy('avance_date', 'DESC') 
                        ->findAll();
                } catch (\Exception $e) {
                    log_message('error', 'Erreur lors de la récupération des recouvrements : ' . $e->getMessage());
                    return false;
                }
            }
            try {
                return $this
                    ->where('is_order',0)
                    ->where('active',1)
                    ->orderBy('avance_date', 'DESC')
                    ->findAll();
            } catch (\Exception $e) {
                log_message('error', 'Erreur lors de la récupération des recouvrements : ' . $e->getMessage());
                return false;
            }
        } else {
            if($id){
                try {
                    return $this->where('user_id',$id)
                        ->where('is_order',0)
                        ->where('active',1)
                        ->where('store_id',$users['store_id'])
                        ->orderBy('avance_date', 'DESC') 
                        ->findAll();
                } catch (\Exception $e) {
                    log_message('error', 'Erreur lors de la récupération des recouvrements : ' . $e->getMessage());
                    return false;
                }
            }
            try {
                return $this
                    ->where('is_order',0)
                    ->where('active',1)
                    ->where('store_id',$users['store_id'])
                    ->orderBy('avance_date', 'DESC')
                    ->findAll();
            } catch (\Exception $e) {
                log_message('error', 'Erreur lors de la récupération des recouvrements : ' . $e->getMessage());
                return false;
            }
        }
    }

    public function fetchSingleAvance(int $avance_id){
        return $this->select('avances.*, products.name as product_name_db, products.prix_vente as product_price')
                    ->join('products', 'products.id = avances.product_id', 'left')
                    ->where('avances.avance_id', $avance_id)
                    ->first();
    }

    public function removeAvance(int $avance_id){
        return $this->delete($avance_id);
    }

    // ✅ CORRECTION : getTotalAvance pour la caissière
    public function getTotalAvance() {
        $session = session();
        $users = $session->get('user');
        $isAdmin = in_array($users['group_name'], ['Conseil', 'Direction']);
        
        try {
            $builder = $this->select('SUM(avance_amount) AS ta')
                           ->where('is_order', 0)
                           ->where('active', 1); // ✅ Ajout du filtre active
            
            if (!$isAdmin) {
                $builder->where('store_id', $users['store_id']); // ✅ Filtre par store pour caissière
            }
            
            return $builder->get()->getRowObject();
        } catch (\Exception $e) {
            log_message('error', 'Erreur lors du total du montant des avances : ' . $e->getMessage());
            return (object) ['ta' => 0]; // ✅ Retourner un objet avec ta = 0 en cas d'erreur
        }
    }

    // ✅ CORRECTION PRINCIPALE : getPaymentModesAvance pour la caissière
    public function getPaymentModesAvance()
    {
        $session = session();
        $users = $session->get('user');
        $isAdmin = in_array($users['group_name'], ['Conseil', 'Direction']);
    
        try {
            $builder = $this->db->table('avances')
                ->select('
                    SUM(avance_amount) AS total,
                    SUM(CASE WHEN LOWER(type_payment) = "mvola" THEN avance_amount ELSE 0 END) AS total_mvola,
                    SUM(CASE WHEN LOWER(type_payment) = "en espèce" THEN avance_amount ELSE 0 END) AS total_espece,
                    SUM(CASE WHEN LOWER(type_payment) = "virement bancaire" THEN avance_amount ELSE 0 END) AS total_virement_bancaire
                ')
                ->where('active', 1)
                ->where('is_order', 0); // ✅ Exclure les avances devenues orders
            
            // ✅ CORRECTION : Ajouter le filtre store_id pour la caissière
            if (!$isAdmin) {
                $builder->where('store_id', $users['store_id']);
            }
            
            $result = $builder->get()->getRowObject();
            
            // ✅ Gérer le cas où il n'y a pas de résultats
            if (!$result) {
                return (object) [
                    'total' => 0,
                    'total_mvola' => 0,
                    'total_espece' => 0,
                    'total_virement_bancaire' => 0
                ];
            }
            
            return $result;
            
        } catch (\Exception $e) {
            log_message('error', 'Erreur getPaymentModesAvance: ' . $e->getMessage());
            return (object) [
                'total' => 0,
                'total_mvola' => 0,
                'total_espece' => 0,
                'total_virement_bancaire' => 0
            ];
        }
    }

    public function getAllAvanceData1(int $id=null) {
        $session = session();
        $users =  $session->get('user');
        $isAdmin = in_array($users['group_name'], ['Conseil', 'Direction']);
        if($isAdmin) {
            if($id){
                try {
                    return $this->where('user_id',$id)
                        ->where('is_order',1)
                        ->where('active',1)
                        ->orderBy('avance_date', 'DESC') 
                        ->findAll();
                } catch (\Exception $e) {
                    log_message('error', 'Erreur lors de la récupération des recouvrements : ' . $e->getMessage());
                    return false;
                }
            }
            try {
                return $this
                    ->where('is_order',1)
                    ->where('active',1)
                    ->orderBy('avance_date', 'DESC')
                    ->findAll();
            } catch (\Exception $e) {
                log_message('error', 'Erreur lors de la récupération des recouvrements : ' . $e->getMessage());
                return false;
            }
        } else {
            if($id){
                try {
                    return $this->where('user_id',$id)
                        ->where('is_order',1)
                        ->where('active',1)
                        ->where('store_id',$users['store_id'])
                        ->orderBy('avance_date', 'DESC') 
                        ->findAll();
                } catch (\Exception $e) {
                    log_message('error', 'Erreur lors de la récupération des recouvrements : ' . $e->getMessage());
                    return false;
                }
            }
            try {
                return $this
                    ->where('is_order',1) // ✅ Correction: devrait être 1, pas 0
                    ->where('active',1) // ✅ Ajout du filtre active
                    ->where('store_id',$users['store_id']) // ✅ Ajout du filtre store
                    ->orderBy('avance_date', 'DESC')
                    ->findAll();
            } catch (\Exception $e) {
                log_message('error', 'Erreur lors de la récupération des recouvrements : ' . $e->getMessage());
                return false;
            }
        }
    }

    public function getAllAvanceData2(int $id=null) {
        $session = session();
        $users =  $session->get('user');
        $isAdmin = in_array($users['group_name'], ['Conseil', 'Direction']);
        if($isAdmin) {
            if($id){
                try {
                    return $this->where('user_id',$id)
                        ->where('is_order',0)
                        ->where('active',0)
                        ->orderBy('avance_date', 'DESC') 
                        ->findAll();
                } catch (\Exception $e) {
                    log_message('error', 'Erreur lors de la récupération des recouvrements : ' . $e->getMessage());
                    return false;
                }
            }
            try {
                return $this
                    ->where('is_order',0)
                    ->where('active',0)
                    ->orderBy('avance_date', 'DESC')
                    ->findAll();
            } catch (\Exception $e) {
                log_message('error', 'Erreur lors de la récupération des recouvrements : ' . $e->getMessage());
                return false;
            }
        } else {
            if($id){
                try {
                    return $this->where('user_id',$id)
                        ->where('is_order',0)
                        ->where('active',0)
                        ->where('store_id',$users['store_id'])
                        ->orderBy('avance_date', 'DESC') 
                        ->findAll();
                } catch (\Exception $e) {
                    log_message('error', 'Erreur lors de la récupération des recouvrements : ' . $e->getMessage());
                    return false;
                }
            }
            try {
                return $this
                    ->where('is_order',0)
                    ->where('active',0)
                    ->where('store_id',$users['store_id'])
                    ->orderBy('avance_date', 'DESC')
                    ->findAll();
            } catch (\Exception $e) {
                log_message('error', 'Erreur lors de la récupération des recouvrements : ' . $e->getMessage());
                return false;
            }
        }
    }

    public function checkExpiredAvance() {
        $now = date('Y-m-d');
        $avances = $this->where('active', '1')
            ->where('deadline <', $now)
            ->findAll();

        if (!empty($avances)) {
            $productModel = new Products();

            foreach ($avances as $avance) {
                $this->update($avance['avance_id'], ['active' => '0']);
                if (!empty($avance['product_id'])) { // ✅ Vérifier que product_id existe
                    $productModel->update($avance['product_id'], ['product_sold' => 0]);
                }
            }
        }
    }

    public function getAvancesNearDeadline($days = 3)
    {
        $alertDate = date('Y-m-d', strtotime("+{$days} days"));
        
        return $this->select('avances.*, users.store_id')
                    ->join('users', 'users.id = avances.user_id')
                    ->where('avances.is_order', 0)
                    ->where('avances.active', 1)
                    ->where('avances.amount_due >', 0)
                    ->where('DATE(avances.deadline)', $alertDate)
                    ->findAll();
    }

    public function getIncompleteAvances(int $id = null)
    {
        $session = session();
        $users = $session->get('user');
        $isAdmin = in_array($users['group_name'], ['Conseil', 'Direction']);

        $builder = $this->where('is_order', 0)
                        ->where('active', 1)
                        ->where('amount_due >', 0);

        if (!$isAdmin) {
            $builder->where('store_id', $users['store_id']);
        }

        if ($id) {
            $builder->where('user_id', $id);
        }

        return $builder->orderBy('avance_date', 'DESC')->findAll();
    }

    public function getCompletedAvances(int $id = null)
    {
        $session = session();
        $users = $session->get('user');
        $isAdmin = in_array($users['group_name'], ['Conseil', 'Direction']);

        $builder = $this->where('is_order', 0)
                        ->where('active', 1)
                        ->where('amount_due', 0);

        if (!$isAdmin) {
            $builder->where('store_id', $users['store_id']);
        }

        if ($id) {
            $builder->where('user_id', $id);
        }

        return $builder->orderBy('avance_date', 'DESC')->findAll();
    }

public function markAsPrinted($avance_id)
{
    try {
        return $this->update($avance_id, [
            'is_printed' => 1
        ]);
    } catch (\Exception $e) {
        log_message('error', 'Erreur markAsPrinted: ' . $e->getMessage());
        return false;
    }
}

/**
 * Marquer une avance comme non imprimée (quand elle est modifiée)
 */
public function markAsNotPrinted($avance_id)
{
    try {
        return $this->update($avance_id, [
            'is_printed' => 0,
            'last_modified_at' => date('Y-m-d H:i:s')
        ]);
    } catch (\Exception $e) {
        log_message('error', 'Erreur markAsNotPrinted: ' . $e->getMessage());
        return false;
    }
}

/**
 * Vérifier si une avance a déjà été imprimée
 */
public function isPrinted($avance_id)
{
    try {
        $avance = $this->find($avance_id);
        return $avance ? (bool)$avance['is_printed'] : false;
    } catch (\Exception $e) {
        log_message('error', 'Erreur isPrinted: ' . $e->getMessage());
        return false;
    }
}
/**
 * Récupérer un produit avec le nom de sa marque
 * @param int $product_id
 * @return array|null
 */
public function getProductWithBrand($product_id)
{
    try {
        return $this->select('products.*, brands.name as brand_name')
                    ->join('brands', 'brands.id = products.marque', 'left')
                    ->where('products.id', $product_id)
                    ->first();
    } catch (\Exception $e) {
        log_message('error', 'Erreur getProductWithBrand: ' . $e->getMessage());
        return null;
    }
}  
// À ajouter dans App\Models\Avance.php

/**
 * ✅ Convertir une avance complète en commande
 * Appelé automatiquement quand amount_due atteint 0
 * 
 * @param int $avance_id
 * @return int|false ID de la commande créée ou false
 */
public function convertToOrder(int $avance_id)
{
    try {
        $avance = $this->find($avance_id);
        
        if (!$avance) {
            log_message('error', "Avance introuvable : {$avance_id}");
            return false;
        }
        
        // ✅ MODIFICATION PRINCIPALE : Vérifier que c'est bien une avance sur TERRE
        if ($avance['type_avance'] !== 'terre') {
            log_message('info', "Avance {$avance_id} de type '{$avance['type_avance']}' - Conversion ignorée (seules les avances TERRE sont converties)");
            return false;
        }
        
        // ✅ Vérifier que l'avance est bien complète
        if ((float)$avance['amount_due'] > 0) {
            log_message('warning', "Avance TERRE {$avance_id} non complète (amount_due={$avance['amount_due']})");
            return false;
        }
        
        // ✅ Vérifier qu'elle n'a pas déjà été convertie
        if ((int)$avance['is_order'] === 1) {
            log_message('info', "Avance TERRE {$avance_id} déjà convertie en commande");
            return false;
        }
        
        // ✅ Vérifier que le produit existe (obligatoire pour avance TERRE)
        if (empty($avance['product_id'])) {
            log_message('error', "Avance TERRE {$avance_id} sans product_id - Impossible de convertir");
            return false;
        }
        
        $db = \Config\Database::connect();
        $db->transStart();
        
        // ✅ 1. Créer la commande
        $orderModel = new \App\Models\Orders();
        $bill_no = 'BILAV-' . strtoupper(substr(md5(uniqid(mt_rand(), true)), 0, 4));
        
        $orderData = [
            'bill_no'              => $bill_no,
            'customer_name'        => $avance['customer_name'],
            'customer_address'     => $avance['customer_address'],
            'customer_phone'       => $avance['customer_phone'],
            'customer_cin'         => $avance['customer_cin'],
            'date_time'            => date('Y-m-d H:i:s'),
            'gross_amount'         => $avance['gross_amount'],
            'net_amount'           => $avance['gross_amount'],
            'discount'             => 0,
            'paid_status'          => 2, // En attente validation caissière
            'user_id'              => $avance['user_id'],
            'store_id'             => $avance['store_id'],
            'service_charge_rate'  => 0,
            'vat_charge_rate'      => 0,
            'vat_charge'           => 0,
            'tranche_1'            => $avance['avance_amount'],
            'tranche_2'            => null,
            'order_payment_mode'   => $avance['type_payment'] ?? 'En espèce',
            'order_payment_mode_1' => null,
        ];
        
        $order_id = $orderModel->insert($orderData);
        
        if (!$order_id) {
            throw new \Exception("Échec création commande pour avance TERRE {$avance_id}");
        }
        
        log_message('info', "✅ Commande {$bill_no} créée depuis avance TERRE {$avance_id}");
        
        // ✅ 2. Créer les items de commande
        $orderItemModel = new \App\Models\OrderItems();
        $productModel = new \App\Models\Products();
        
        $product = $productModel->find($avance['product_id']);
        
        if ($product) {
            $orderItemModel->insert([
                'order_id'   => $order_id,
                'product_id' => $avance['product_id'],
                'rate'       => $avance['gross_amount'],
                'qty'        => 1,
                'amount'     => $avance['gross_amount'],
            ]);
            
            log_message('info', "Item ajouté : produit {$avance['product_id']} (TERRE)");
            
            // ✅ Le produit reste marqué comme vendu (product_sold = 1)
            // Il sera géré dans la commande maintenant
        } else {
            log_message('warning', "Produit {$avance['product_id']} introuvable pour avance TERRE {$avance_id}");
        }
        
        // ✅ 3. Marquer l'avance comme convertie
        $this->update($avance_id, [
            'is_order' => 1,
            'active'   => 0, // Désactiver l'avance (elle devient commande)
        ]);
        
        $db->transComplete();
        
        if ($db->transStatus() === false) {
            log_message('error', "Transaction échouée pour avance TERRE {$avance_id}");
            return false;
        }
        
        // ✅ 4. Notification à la caissière
        $notificationController = new \App\Controllers\NotificationController();
        $notificationController->createNotification(
            "Nouvelle commande issue d'une avance TERRE complète - {$bill_no}",
            "Caissière",
            (int)$avance['store_id'],
            "orders"
        );
        
        log_message('info', "✅ Avance TERRE {$avance_id} convertie en commande {$order_id} ({$bill_no})");
        
        return $order_id;
        
    } catch (\Exception $e) {
        log_message('error', "Erreur conversion avance TERRE→commande : " . $e->getMessage());
        return false;
    }
}

/**
 * ✅ Hook appelé automatiquement lors du paiement d'une avance
 * Intégrer ceci dans votre fonction de paiement existante
 */
public function afterPayment(int $avance_id)
{
    $avance = $this->find($avance_id);
    
    if (!$avance) {
        return false;
    }
    
    // ✅ Si l'avance est maintenant complète ET que c'est une avance TERRE
    if ((float)$avance['amount_due'] <= 0 && $avance['type_avance'] === 'terre') {
        log_message('info', "💰 Avance TERRE {$avance_id} complète ! Conversion automatique en commande...");
        return $this->convertToOrder($avance_id);
    }
    
    // ✅ Si c'est une avance MER complète, on ne fait rien (elle reste dans la liste)
    if ((float)$avance['amount_due'] <= 0 && $avance['type_avance'] === 'mere') {
        log_message('info', "💰 Avance MER {$avance_id} complète ! Elle reste dans la liste des avances.");
    }
    
    return true;
}

    /**
     * ✅ Générer un numéro de facture unique
     */
    private function generateBillNumber($store_id)
    {
        $db = \Config\Database::connect();
        
        // Récupérer le dernier numéro pour ce store
        $query = $db->query(
            "SELECT bill_no FROM orders WHERE store_id = ? ORDER BY id DESC LIMIT 1",
            [$store_id]
        );
        
        $result = $query->getRow();
        
        if ($result && preg_match('/(\d+)$/', $result->bill_no, $matches)) {
            $lastNumber = intval($matches[1]);
            $newNumber = $lastNumber + 1;
        } else {
            $newNumber = 1;
        }
        
        // Format: BILL-STORE{store_id}-{number}
        return 'BILL-STORE' . $store_id . '-' . str_pad($newNumber, 5, '0', STR_PAD_LEFT);
    }

    /**
     * ✅ Récupérer toutes les avances complètes non converties
     */
    public function getCompletedNotConverted()
    {
        return $this->where('amount_due', 0)
                    ->where('is_order', 0)
                    ->where('active', 1)
                    ->where('type_avance', 'terre') // ✅ Uniquement TERRE à convertir
                    ->findAll();
    }

        /**
     * ✅ NOUVELLE MÉTHODE : Récupérer les avances MER complètes (pour statistiques)
     */
    public function getCompletedMerAvances()
    {
        $session = session();
        $users = $session->get('user');
        $isAdmin = in_array($users['group_name'], ['Conseil', 'Direction']);

        $builder = $this->where('amount_due', 0)
                        ->where('active', 1)
                        ->where('type_avance', 'mere');

        if (!$isAdmin) {
            $builder->where('store_id', $users['store_id']);
        }

        return $builder->orderBy('avance_date', 'DESC')->findAll();
    }

}