<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Services\FifoStockService;
use Barryvdh\DomPDF\Facade\Pdf;
use Illuminate\Support\Facades\DB;
use App\Models\ArticlesStock;
use App\Models\Stock_categorie;
use App\Models\BonRequisitionsStock;
use App\Models\DetailBonRequisitionStock;
use App\Models\DetailBordereauxSortieStock;
use App\Models\Stock_divers_initial;
use App\Models\BordereauxSortieStock; 
use App\Models\BordereauxEntreeStockDetail; 
use App\Models\MouvementsStock; 
use App\Models\BordereauxEntreeStock;
use App\Models\BonCommandeAchat;
use App\Models\Service;  
use App\Models\User;
use Carbon\Carbon;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Validator;

class MouvementStockDiverController extends Controller
{
   protected $fifoStock;

    public function __construct(FifoStockService $fifoStock)
    {
         $this->middleware('auth');
        $this->fifoStock = $fifoStock;
    }
        public function all_bons_sortis()
        {
            $bons_sortis = DB::table('bordereaux_sortie_stocks')
             ->join('bon_requisitions_stocks', 'bon_requisitions_stocks.id_requisition', '=', 'bordereaux_sortie_stocks.requisition_id')
            ->leftjoin('users', 'users.id', '=', 'bordereaux_sortie_stocks.employe_transporteur_id')
            ->select('bordereaux_sortie_stocks.*', 'users.name','bon_requisitions_stocks.*')
            ->orderBy('bordereaux_sortie_stocks.statut_sortie','asc')
            ->get();
        
            return view('stockDivers_views.stock_divers.all_bons_sortis', compact('bons_sortis'));
        }
public function genere_bon_sortie(Request $request)
{
    $request->validate([
        'id_requisition' => 'required|exists:bon_requisitions_stocks,id_requisition',
        'employe_transporteur_id' => 'required|exists:users,id',
        'date_sortie' => 'required|date',
    ]);
    $numero_requisition  = $request->id_requisition;
    // Cette méthode générera un bon de sortie pour les articles approuvés d'une réquisition en stock
    // 1. Récupérer le bon de réquisition
    $bon_requisition = BonRequisitionsStock::find($numero_requisition);
    if (!$bon_requisition) {
        return redirect()->back()->withErrors("Bon de réquisition introuvable."); 
    }
$verifierBonSortie = DB::table('bordereaux_sortie_stocks')
    ->where('requisition_id', $numero_requisition)
    ->exists();

if ($verifierBonSortie) {
    return redirect()->back()
        ->withErrors("Le bordereau de sortie existe déjà pour ce bon de réquisition.");
}
    // 2. Récupérer les articles approuvés pour ce bon de réquisition
    $articles_approuves = DB::table('detail_bon_requisition_stocks')
        ->join('articles_stocks', 'articles_stocks.id_article', '=', 'detail_bon_requisition_stocks.article_id')
        ->leftJoin('stock_divers_initials', 'stock_divers_initials.article_id', '=', 'articles_stocks.id_article')
        ->where('detail_bon_requisition_stocks.requisition_id', $numero_requisition)
        ->where('detail_bon_requisition_stocks.status_demande', 2) // 2 = approuvé
        ->select(
            'detail_bon_requisition_stocks.*',
            'articles_stocks.nom_article',
            'stock_divers_initials.*'
        )
        ->get();

    if ($articles_approuves->isEmpty()) {
        return back()->withErrors("Aucun article approuvé trouvé pour ce bon de réquisition.");
    }

    // 3. Générer le bon de sortie (logique à implémenter selon vos besoins, ex: créer une nouvelle table "bon_sorties" et y insérer les données)

    // Exemple d'insertion dans une table "bon_sorties" (à adapter selon votre structure de base de données)
    //DAP=Direction Approvisionement 
   //generer un numero_bord_sortie  unique pour le bon de sortie de format : DAP/BS/numero_bord_sortie/annee ex : DAP/BS/0001/2026
    $prefixe = 'DAP';
    $code_bon = 'BS';
    $annee= now()->year;

    $result = DB::transaction(function () use ($prefixe,$code_bon,$annee) {

        $dernierNumero = DB::table('bordereaux_sortie_stocks')
            ->where('numero_bord_sortie', 'like', $prefixe .'/' .$code_bon . '/%/' . $annee)
            ->lockForUpdate()
            ->orderBy('numero_bord_sortie', 'desc')
            ->value('numero_bord_sortie');

        if ($dernierNumero) {
            $parts = explode('/', $dernierNumero);
            $dernierCompteur = (int) $parts[2]; // Récupérer la partie compteur
            $nouveauCompteur = $dernierCompteur + 1;
        } else {
            $nouveauCompteur = 1;
        }

        // 🚫 Bloquer si dépassement
        if ($nouveauCompteur > 9999) {
            return ['error' => true];
        }

        $numero = sprintf('%s/%s/%04d/%d', $prefixe, $code_bon, $nouveauCompteur, $annee);

        return [
            'error' => false,
            'numero' => $numero
        ];
    });

    // ✅ 5. Vérifier erreur compteur
    if ($result['error']) {
        return redirect()->back()->with(
            'error',
            "Erreur : le nombre maximum de bordeureaux de sortie est atteint pour cette année ".$annee
        );
    }
    $bon_sortie = new BordereauxSortieStock();
    $bon_sortie->numero_bord_sortie  = $result['numero']; // Générer un numéro unique pour le bon de sortie
    $bon_sortie->requisition_id = $numero_requisition;
    $bon_sortie->employe_transporteur_id = $request->employe_transporteur_id;
    $bon_sortie->date_sortie = $request->date_sortie;
    $bon_sortie->statut_sortie = 1; // ou encours
    $bon_sortie->employeId_stock = Auth::id(); // L'employé qui gère le stock et valide la sortie
    $bon_sortie->save();


   return redirect()->route('form_sortir_article_demande', ['id' => $numero_requisition])
        ->with('success', "Bon de sortie généré avec succès !");
}
public function form_sortir_article_demande($id)
{  
    $requisition = BonRequisitionsStock::find($id);
    if (!$requisition) {
        return redirect()->back()->withErrors("Bon de réquisition introuvable.");
    }
    //recuperer categorie du stock pour afficher les articles de ce stock dans le detail du bon de requisition
    $categorie_stock = DB::table('stock_categories')
        ->where('stock_id', $requisition->stock_id)->first();

            // Récupérer les articles demandés avec leurs détails pour le bon de réquisition et joindre avec la table articles_stocks et les stock_initial pour avoir les informations des articles

           $articles_approuves = DB::table('detail_bon_requisition_stocks')
        ->join('articles_stocks', 'articles_stocks.id_article', '=', 'detail_bon_requisition_stocks.article_id')
        ->leftJoin('stock_divers_initials', 'stock_divers_initials.article_id', '=', 'articles_stocks.id_article')
        ->where('detail_bon_requisition_stocks.requisition_id', $id)
        // ->where('detail_bon_requisition_stocks.status_demande', 2) // 2 = approuvé
        ->select(
            'detail_bon_requisition_stocks.*',
            'articles_stocks.nom_article',
            'stock_divers_initials.*'
        )
        ->get();
        $bon_sortie_id = BordereauxSortieStock::where('requisition_id',$id)->value('id_bordereau_sortie');
        $statut_requisition = $requisition->statut_requisition;
      
    return view('stockDivers_views.stock_divers.form_sortir_article_demande', compact('requisition',  'articles_approuves','bon_sortie_id','statut_requisition'));
}
public function save_sortie_article(Request $request)
{
    // 1. Validation des données
    $validator = Validator::make($request->all(), [
        'bon_sortie_id' => 'required|numeric|exists:bordereaux_sortie_stocks,id_bordereau_sortie',
        'qte_sortie'    => 'required|array',
        'qte_sortie.*'  => 'required|numeric|min:1',
        'pu_sortie'     => 'required|array',
        'pu_sortie.*'   => 'required|numeric|min:0',
        'observation_sortie' => 'nullable|array',
        'observation_sortie.*' => 'nullable|string|max:200'
    ]);

    if ($validator->fails()) {
        return back()->withErrors($validator)->withInput();
    }

    // 2. Récupération du bordereau de sortie
    $bon_sortie = BordereauxSortieStock::where('id_bordereau_sortie',$request->bon_sortie_id)->first();
    if (!$bon_sortie) {
        return back()->withErrors("Bordereau de sortie introuvable.")->withInput();
    }

    // 3. Récupération des détails de la réquisition associée
    $details_requisition = DB::table('detail_bon_requisition_stocks')
        ->where('requisition_id', $bon_sortie->requisition_id)
        ->get();

    if ($details_requisition->isEmpty()) {
        return back()->withErrors("Aucun détail trouvé pour cette réquisition.")->withInput();
    }

    // 4. Récupération des tableaux saisis (clés = id_detail_bon_requisition)
    $quantites      = $request->input('qte_sortie');
    $prix_unitaires = $request->input('pu_sortie');
    $observations   = $request->input('observation_sortie', []);

    // 5. Vérification que chaque ID soumis existe bien dans la réquisition
    $ids_soumis = array_keys($quantites);
     $ids_valides = $details_requisition->pluck('id_detail_bon_requisition')->toArray();
     
  
    foreach ($ids_soumis as $id_detail) {
        if (!in_array($id_detail, $ids_valides)) {
            return back()->withErrors("Le détail de réquisition ID $id_detail n'existe pas.")->withInput();
        }
    }

    // 6. Préparation des libellés pour les mouvements
    $numero_bord_sortie = $bon_sortie->numero_bord_sortie;
    $numero_requisition = $bon_sortie->requisition_id;
    $date_mouvement = $bon_sortie->date_sortie;

// 7. Boucle sur chaque article à sortir
foreach ($ids_soumis as $id_detail) {
    $qte = $quantites[$id_detail];
    $pu  = $prix_unitaires[$id_detail];
    $obs = $observations[$id_detail] ?? null;

    $detail = $details_requisition->firstWhere('id_detail_bon_requisition', $id_detail);

    // Vérification du stock
    if ($qte > $detail->qte_demandee_requisition) {
        return back()->withErrors("Quantité sortie pour l'article ID {$detail->article_id} dépasse la quantité demandée.")->withInput();
    }

    // 7.1 Enregistrement dans la table des détails du bon de sortie
    $bon_sortie_detail = new DetailBordereauxSortieStock();
    $bon_sortie_detail->bordereau_sortie_id = $bon_sortie->id_bordereau_sortie; // bon_sortie_id
    $bon_sortie_detail->article_id           = $detail->article_id;            // AJOUT : article_id
    $bon_sortie_detail->detail_bon_requisition_id = $id_detail;
    $bon_sortie_detail->qte_sortie           = $qte;
    $bon_sortie_detail->pu_sortie            = $pu;
    $bon_sortie_detail->observation_sortie   = $obs;
    $bon_sortie_detail->save();

// 7.2 Création du mouvement de stock
// Récupérer l'article pour connaître le stock réel et le CUMP avant mouvement
$article = Stock_divers_initial::where('article_id',$detail->article_id)->first();

if (!$article) {
    return back()->withErrors("Article introuvable (ID: {$detail->article_id}). dans la table d'initialisation du stock")->withInput();
}
// Quantité avant mouvement (stock actuel)
$qte_avant = $article->qte_stock;       // À adapter selon votre colonne
$pu_avant  = $article->cump_article;         // À adapter selon votre colonne

// Vérifier qu'il y a assez de stock
if ($qte_avant < $qte) {
    return back()->withErrors("Stock insuffisant pour l'article {$article->nom_article}. Stock actuel : $qte_avant, demandé : $qte.")->withInput();
}

$qte_apres = $qte_avant - $qte;
$cout_total_apres = $qte_apres * $pu_avant; // Le CUMP ne change pas en sortie

// Mouvement de sortie
$mvt = new MouvementsStock();
$mvt->article_id       = $detail->article_id;
$mvt->type_mvt_id      = 2;  // 2 = sortie par réquisition (référence à table type_mouvements)
$mvt->date_mouvement   = $date_mouvement ?? Carbon::now('Africa/Bujumbura');
$mvt->qte_avant_mvt    = $qte_avant;
$mvt->pu_avant_mvt     = $pu_avant;
$mvt->qte_sortie       = $qte;
$mvt->pu_sortie        = $pu;        // Coût de sortie (généralement = CUMP avant)
$mvt->qte_final    = $qte_apres;
$mvt->pu_final     = $pu_avant;   // CUMP inchangé après sortie
$mvt->cout_total_final = $cout_total_apres;
$mvt->numero_reference = $bon_sortie->numero_bord_sortie; // ex: "DRH/BS/00012/2026"
$mvt->motif_mvt        = "Sortie pour réquisition n° $numero_requisition sur bon de sortie n° $numero_bord_sortie";
$mvt->created_by       = Auth::id();  // Stocker l'ID, pas le nom (clé étrangère vers users)
$mvt->bord_entree_id   = null;        // Pas d'entrée associée, c'est une sortie
$mvt->save();

// 7.3 Mise à jour du stock de l'article
$article->qte_stock = $qte_apres;
//tous les articles sorties
$article->qte_sortie += $qte;
//sortir pour les reserver
$article->qte_reserver -= $qte;
// Le CUMP reste inchangé en cas de sortie (pas de recalcul)
$article->save();

// 7.4 Mise à jour du détail de la réquisition et bon sortie 
DB::table('detail_bon_requisition_stocks')
    ->where('id_detail_bon_requisition', $id_detail)
    ->update([
        'qte_sortie' => $qte,
        'observation_sortie' => $obs,
        'status_demande' => 4, // 4 = sorti
    ]);
    }
    //changer le statut du bon requisition du depart
    DB::table('bon_requisitions_stocks')->where('id_requisition', $bon_sortie->requisition_id)
    ->update(['statut_requisition' => 3]); //deja sortie
$bon_sortie->statut_sortie =2; //deja sortie
$bon_sortie->save();
    // 8. Redirection finale
    return redirect()->route('detail_requisition_stock', ['id' => $bon_sortie->requisition_id])
        ->with('success', "Articles sortis avec succès !");
}

public function print_bon_sortie($id)
{
    // 1. Récupérer l'en-tête du bordereau (sans jointure sur detail qui pourrait multiplier les lignes)
    $bordereau_info = BordereauxSortieStock::leftJoin('users', 'users.id', '=', 'bordereaux_sortie_stocks.employe_transporteur_id')
        ->where('requisition_id', $id)
        ->select('bordereaux_sortie_stocks.*', 'users.name as transporteur_nom')
        ->first();

    if (!$bordereau_info) {
        return redirect()->back()->with('error', 'Numéro de bon de sortie introuvable !');
    }

    // 2. Récupérer les détails du bordereau avec le nom de l'article
    $details_bon_sortis = DB::table('detail_bordereaux_sortie_stocks')
        ->join('articles_stocks', 'articles_stocks.id_article', '=', 'detail_bordereaux_sortie_stocks.article_id')
        ->where('detail_bordereaux_sortie_stocks.bordereau_sortie_id', $bordereau_info->id_bordereau_sortie)
        ->select('detail_bordereaux_sortie_stocks.*', 'articles_stocks.nom_article')
        ->get();

    // 3. Ajouter le prix total et le numéro de ligne à chaque détail
    foreach ($details_bon_sortis as $index => $detail) {
        $detail->prix_total = $detail->qte_sortie * $detail->pu_sortie;
        $detail->numero = $index + 1;
    }

    // 4. Récupérer le nom du magasinier (employeId_stock)
    $nom_magasinier = null;
    if ($bordereau_info->employeId_stock) {
        $nom_magasinier = User::where('id', $bordereau_info->employeId_stock)->value('name');
    }

    // 5. Transporteur déjà récupéré via leftJoin (alias transporteur_nom)
    $transporteur = $bordereau_info->transporteur_nom ?? null;

    // 6. Formater la date de sortie
    $date_sortie = $bordereau_info->date_sortie 
        ? Carbon::parse($bordereau_info->date_sortie)->format('d/m/Y') 
        : now()->format('d/m/Y');
 $service_id =BonRequisitionsStock::where('id_requisition',$bordereau_info->requisition_id)->value('service_id');    
$service_demandeur = Service::where('idservice', $service_id)->value('nom_service') ?? null;

    // 7. Informations société et signataires pour la vue
    $societe = [
        'nom'    => 'ITRACOM',
        'adresse'=> "Bujumbura-Ngagara, Quartier Industriel, Avenue de l'Agriculture",
        'tel'    => '+257 22 25 43 21',
        'email'  => 'info@itracom.bi',
        'nom_magasinier' => $nom_magasinier,
        'transporteur'   => $transporteur,
        'service_demandeur' =>$service_demandeur
    ];

    // 8. Génération du PDF
    $pdf = Pdf::loadView('stockDivers_views.formulaires.bordereau_sortie_pdf', [
        'bordereau'        => $bordereau_info,        // pour les infos générales
        'details_bon_sortis' => $details_bon_sortis,  // tableau des lignes
        'societe'          => $societe,
        'date_sortie'      => $date_sortie,
    ]);
    // Format A4 portrait
    return $pdf->setPaper('a4', 'portrait')
              ->stream('bordereau_sortie_' . $bordereau_info->numero_bord_sortie . '.pdf');
}
       public function all_bon_entrees()
        {
            $bons_entrees = DB::table('bordereaux_entree_stocks')
             ->join('bon_commande_achats', 'bon_commande_achats.id_bon_commande_achat', '=', 'bordereaux_entree_stocks.bon_commande_id')
            ->leftjoin('users', 'users.id', '=', 'bordereaux_entree_stocks.receptionnaire_id')
            ->select('bordereaux_entree_stocks.*', 'users.name','bon_commande_achats.*')
            ->orderBy('bordereaux_entree_stocks.id_bordereau_entree_stock','asc')
            ->get();
        
            return view('stockDivers_views.stock_divers.all_bon_entrees', compact('bons_entrees'));
        }
    public function generer_bon_entree(Request $request){
        $request->validate([
            'bon_commande_id'        => 'required|exists:bon_commande_achats,id_bon_commande_achat',
            'expediteur_id'         => 'required|exists:users,id',
            'date_bordereau_entree'  => 'required|date|before_or_equal:today',
        ]);
        $verify= BordereauxEntreeStock::where('bon_commande_id',$request->bon_commande_id)->first();
        if( $verify){
          return back()
            ->with('error', "Bordereau d'entrée bon_commande_id:{$request->bon_commande_id} existe deja");   
        }
// --------------------------------------------------------------------------
    $prefixe = 'DAP';
    $code_bon = 'BE';
    $annee= now()->year;

    $result = DB::transaction(function () use ($prefixe,$code_bon,$annee) {

        $dernierNumero = DB::table('bordereaux_entree_stocks')
            ->where('numero_bordereau_entree', 'like', $prefixe .'/' .$code_bon . '/%/' . $annee)
            ->lockForUpdate()
            ->orderBy('numero_bordereau_entree', 'desc')
            ->value('numero_bordereau_entree');

        if ($dernierNumero) {
            $parts = explode('/', $dernierNumero);
            $dernierCompteur = (int) $parts[2]; // Récupérer la partie compteur
            $nouveauCompteur = $dernierCompteur + 1;
        } else {
            $nouveauCompteur = 1;
        }
        // 🚫 Bloquer si dépassement
        if ($nouveauCompteur > 9999) {
            return ['error' => true];
        }
        $numero = sprintf('%s/%s/%04d/%d', $prefixe, $code_bon, $nouveauCompteur, $annee);

        return [
            'error' => false,
            'numero' => $numero
        ];
    });

    // ✅ 5. Vérifier erreur compteur
    if ($result['error']) {
        return redirect()->back()->with(
            'error',
            "Erreur : le nombre maximum de bordeureaux d'entrée est atteint pour cette année ".$annee
        );
    }
        // Créer le bordereau
        $bordereau = BordereauxEntreeStock::create([
            'numero_bordereau_entree' => $result['numero'],
            'date_bordereau_entree'   => $request->date_bordereau_entree,
            'expediteur_id'           => $request->expediteur_id ,
            'receptionnaire_id'       => Auth::id(), // utilisateur connecté
            'bon_commande_id'         => $request->bon_commande_id,
            'status_bordereau_entree'=> 1, // en attente
        ]);

        // Vous pouvez ensuite déclencher d'autres actions (mise à jour du stock, etc.)

        return redirect()->route('all_bon_entrees')->with('success', 'Bordereau d\'entrée généré avec succès ! Numéro : ' . $result['numero']);
    
}

public function form_entrer_article_stock($id)
{  
      $bonCommande= BonCommandeAchat::where('id_bon_commande_achat',$id)->first();
        if( !$bonCommande){
          return back()
            ->with('error', "Bon de commande introuvable");   
        }
 
  $articles_commandes = DB::table('detail_bon_commande_achats')
        ->join('articles_stocks', 'articles_stocks.id_article', '=', 'detail_bon_commande_achats.article_id')
        ->leftJoin('stock_divers_initials', 'stock_divers_initials.article_id', '=', 'articles_stocks.id_article')
          ->leftjoin('unite_mesures','unite_mesures.id_unite_mesure' ,'=','articles_stocks.unite_mesure_id')
        ->where('detail_bon_commande_achats.bon_commande_id', $id)
      ->select(
            'detail_bon_commande_achats.*',
            'articles_stocks.nom_article',
            'stock_divers_initials.*','unite_mesures.unite_mesure as unite'
        )->get();
        $bon_entree_id =BordereauxEntreeStock::where('bon_commande_id',$id)->value('id_bordereau_entree_stock'); 
        $status_bon_commande = '';

      
    return view('stockDivers_views.stock_divers.form_entrer_article_stock', compact('bonCommande',  'articles_commandes','bon_entree_id','status_bon_commande'));
}
// ---------------------------------------
   public function saveEntreeArticles(Request $request)
    {
        $request->validate([
            'bordereau_entree_id' => 'required|exists:bordereaux_entree_stocks,id_bordereau_entree_stock',
            'article_id' => 'required|array',
            'qte_entree' => 'required|array',
            'qte_entree.*' => 'nullable|numeric|min:0',
            'pu_entre' => 'required|array',
            'pu_entre.*' => 'nullable|numeric|min:0',
            'observation_entree' => 'array',
        ]);

        $bordereauId = $request->bordereau_entree_id;
        $bordereau = BordereauxEntreeStock::findOrFail($bordereauId);

        DB::beginTransaction();
        try {
            foreach ($request->article_id as $detailId => $articleId) {
                $qte = $request->qte_entree[$detailId] ?? 0;
                $pu = $request->pu_entre[$detailId] ?? 0;
                $observation = $request->observation_entree[$detailId] ?? null;

                if ($qte > 0) {
                    // 1. Enregistrer le détail du bordereau d'entrée
                    BordereauxEntreeStockDetail::create([
                        'bordereau_entree_id' => $bordereauId,
                        'article_id' => $articleId,
                        'qte_entree' => $qte,
                        'pu_entre' => $pu,
                        'observation_entree' => $observation,
                    ]);

                    // 2. Enregistrer le mouvement de stock (entrée)
                    MouvementsStock::create([
                        'article_id' => $articleId,
                        'type_mvt_id' => 1, //entree,
                        'qte_entree' => $qte,
                        'pu_entree' => $pu,
                        'bord_entree_id' =>  $bordereauId,
                        'date_mouvement' => $bordereau->date_bordereau_entree,
                        'numero_reference' => $bordereau->numero_bordereau_entree,
                        'created_by' => Auth::id(),
                        'motif_mvt' =>"entree par bon de commande No ".$bordereau->numero_bordereau_entree,
                    ]);

                    // 3. Mettre à jour le stock initial (table stock_divers_initials)
                    $stock = Stock_divers_initial::firstOrNew(['article_id' => $articleId]);
                    $stock->qte_stock = ($stock->qte_stock ?? 0) + $qte;
                    $stock->qte_disponible = ($stock->qte_disponible ?? 0) + $qte;
                    $stock->cump_article = $pu; //faire le cump
                    $stock->initialiser_par = Auth::id();
                    $stock->initialiser_le = now();
                    $stock->save(); 
                }
            }
            $bordereau->status_bordereau_entree = 2;
            $bordereau->save();

            DB::commit();
            return redirect()->route('all_bon_entrees')->with('success', 'Articles enregistrés avec succès dans le stock.');
        } catch (\Exception $e) {
            DB::rollBack();
            return back()->withErrors('Erreur lors de l\'enregistrement : ' . $e->getMessage());
        }
    } 

public function print_bon_entree($id)
{
    // 1. Récupérer l'en-tête du bordereau (sans jointure sur detail qui pourrait multiplier les lignes)
    $bordereau_info = BordereauxEntreeStock::leftJoin('users', 'users.id', '=', 'bordereaux_entree_stocks.expediteur_id')
        ->where('id_bordereau_entree_stock', $id)
        ->select('bordereaux_entree_stocks.*', 'users.name as expediteur')
        ->first();

    if (!$bordereau_info) {
        return redirect()->back()->with('error', 'Numéro de bon d entrée introuvable !');
    }

    // 2. Récupérer les détails du bordereau avec le nom de l'article
    $details_bon_entrees = DB::table('bordereaux_entree_stock_details')
        ->join('articles_stocks', 'articles_stocks.id_article', '=', 'bordereaux_entree_stock_details.article_id')
        ->leftjoin('unite_mesures','unite_mesures.id_unite_mesure' ,'=','articles_stocks.unite_mesure_id')
        ->where('bordereaux_entree_stock_details.bordereau_entree_id', $id)
        ->select('bordereaux_entree_stock_details.*', 'articles_stocks.nom_article','unite_mesures.unite_mesure as unite')
        ->get();

    // 3. Ajouter le prix total et le numéro de ligne à chaque détail
    foreach ($details_bon_entrees as $index => $detail) {
        $detail->prix_total = $detail->qte_entree * $detail->pu_entre;
        $detail->numero = $index + 1;
    }

    // 4. Récupérer le nom du magasinier (receptionnaire_id)
    $nom_magasinier = null;
    if ($bordereau_info->receptionnaire_id) {
        $nom_magasinier = User::where('id', $bordereau_info->receptionnaire_id)->value('name');
    }

    // 5. Transporteur déjà récupéré via leftJoin (alias expediteur_id)
    $expediteur = User::where('id', $bordereau_info->expediteur_id)->value('name') ?? null;

    // 6. Formater la date de sortie
    $date_bordereau_entree = $bordereau_info->date_bordereau_entree 
        ? Carbon::parse($bordereau_info->date_bordereau_entree)->format('d/m/Y') 
        : now()->format('d/m/Y');
 $service_id =BonRequisitionsStock::where('id_requisition',$bordereau_info->requisition_id)->value('service_id');    

    // 7. Informations société et signataires pour la vue
    $societe = [
        'nom'    => 'ITRACOM',
        'adresse'=> "Bujumbura-Ngagara, Quartier Industriel, Avenue de l'Agriculture",
        'tel'    => '+257 22 25 43 21',
        'email'  => 'info@itracom.bi',
        'nom_magasinier' => $nom_magasinier,
        'expediteur'   => $expediteur,
        'service_expediteur' => 'Service des Achats'
    ];

    // 8. Génération du PDF
    $pdf = Pdf::loadView('stockDivers_views.formulaires.print_bon_entree', [
        'bordereau'        => $bordereau_info,        // pour les infos générales
        'details_bon_entrees' => $details_bon_entrees,  // tableau des lignes
        'societe'          => $societe,
        'date_bordereau_entree'  => $date_bordereau_entree,
    ]);
  // Format A4 portrait
    return $pdf->setPaper('a4', 'portrait')
              ->stream('bordereau_entree_' . $bordereau_info->numero_bordereau_entree . '.pdf');
}

public function saveEntreeArticles_traiterEntree(Request $request, $bonEntreeId)
{
    // 1. Validation
    $request->validate([
        'bordereau_entree_id' => 'required|exists:bordereaux_entree_stocks,id_bordereau_entree_stock',
        'article_id' => 'required|array',
        'qte_entree' => 'required|array',
        'qte_entree.*' => 'nullable|numeric|min:0',
        'pu_entre' => 'required|array',
        'pu_entre.*' => 'nullable|numeric|min:0',
        'observation_entree' => 'nullable|array',
    ]);

    try {
        // 2. Récupérer le bordereau d'entête
        $bonEntree = BordereauxEntreeStock::findOrFail($bonEntreeId);

        // Vérifier que le bordereau n'est pas déjà traité
        if ($bonEntree->status_bordereau_entree === 'traite') {
            return redirect()->back()->with('error', 'Ce bon d’entrée a déjà été traité.');
        }

        // 3. Parcourir les tableaux pour créer les détails et appeler le FIFO
        $articles = $request->article_id;
        $qtes = $request->qte_entree;
        $pus = $request->pu_entre;
        $observations = $request->observation_entree ?? [];

        foreach ($articles as $index => $articleId) {
            $quantite = $qtes[$index] ?? 0;
            if ($quantite <= 0) continue; // ignorer les lignes vides

            $prix = $pus[$index] ?? 0;
            $observation = $observations[$index] ?? null;

            // 3a. Créer la ligne détail du bordereau d'entrée
            $detail = BordereauxEntreeStockDetail::create([
                'bordereau_entree_id' => $bonEntreeId,
                'article_id' => $articleId,
                'qte_entree' => $quantite,
                'pu_entre' => $prix,
                'observation_entree' => $observation,
            ]);

            // 3b. Appeler le service FIFO pour cette ligne (entrée en stock)
         $this->fifoStock->entree(
                articleId: $articleId,
                quantite: $quantite,
                prixUnitaire: $prix, 
                date: $bonEntree->date_bordereau_entree,
                referenceType: 1, // ou une constante : BON_ENTREE
                referenceId: $bonEntreeId,
                motif: 'Entrée par bon de commande N° ' . $bonEntree->numero_bordereau_entree,
                observation: $observation
            );
        }

        // 4. Marquer le bordereau comme traité
        $bonEntree->update(['status_bordereau_entree' => 2]);

        return redirect()->route('all_bon_entrees')->with('success', 'Articles enregistrés avec succès dans le stock (FIFO).');

    } catch (Exception $e) {
        return redirect()->back()->with('error', 'Erreur : ' . $e->getMessage());
    }
}

public function traiterSortie(Request $request, $bordereauId)
{
    try {
        $bordereau = BordereauSortie::with('lignes')->findOrFail($bordereauId);

        if ($bordereau->statut === 2) {
            return redirect()->back()->with('error', 'Ce bordereau a déjà été traité.');
        }

        foreach ($bordereau->lignes as $ligne) {
            $this->fifoStock->sortie(
                $ligne->article_id,
                $ligne->quantite_sortie,
                $bordereau->date_sortie,
                'bordereau_sortie',
                $bordereau->id,
                'Demande interne'
            );
        }

        $bordereau->update(['statut' => 2]);

        return redirect()->route('stocks.index')
            ->with('success', 'Sortie de stock enregistrée avec succès (FIFO).');

    } catch (Exception $e) {
        return redirect()->back()
            ->with('error', 'Erreur lors de la sortie : ' . $e->getMessage());
    }
}

}
