<?php

namespace App\Http\Controllers;

use App\Models\Magasin;
use App\Models\Mouvement;
use App\Models\Produit;
use App\Models\Stock;
use App\Models\Transfert;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;

class TransfertStockController extends Controller
{
    /**
     * Liste des transfert de stock entre magasin
     */
    public function index()
    {
        $transferts = Transfert::with(['magasinOrigine', 'magasinDestination', 'produit'])->latest()->paginate(15)->withQueryString();
        $magasins = Magasin::orderBy('nom')->get(['id', 'nom']);
        $produits = Produit::orderBy('designation')->get(['id', 'designation', 'reference']);

        return view('transferts.index', compact('transferts', 'magasins', 'produits'));
    }

    /**
     * Créer un nouveau transfert de stock entre magasin
     */
    public function store(Request $request)
    {
        $validated = $request->validate([
            'magasin_origine_id' => 'required|exists:magasins,id',
            'magasin_destination_id' => 'required|exists:magasins,id',
            'produit_id' => 'required|exists:produits,id',
            'quantite' => 'required|integer|min:1',
            'date_transfert' => 'required|date',
        ]);

        // Vérification magasin origine != destination
        if ($validated['magasin_origine_id'] == $validated['magasin_destination_id']) {
            return redirect()->route('transferts.index')
                ->with('error', 'Le magasin d\'origine doit être différent du magasin de destination');
        }

        DB::transaction(function () use ($validated) {

            /**
             *  Calcul du stock actuel dans le magasin d'origine avec verrouillage
             * lockForUpdate() : verrouille la ligne pour la transaction
             * selectRaw() : exécute une requête SQL brute
             * value('stock') : retourne la valeur de la colonne stock
             * COALESCE(SUM(CASE WHEN type = 'entree' THEN quantite WHEN type = 'sortie' THEN -quantite END),0) as stock : calcule le stock actuel en tenant compte des mouvements entrées et sorties
             * 0 : valeur par défaut si la somme est nulle
             * la valeur de stock sera la somme des entrées moins les sorties
             * stockDisponible : stock actuel dans le magasin d'origine
             */
            $stockDisponible = Mouvement::where('produit_id', $validated['produit_id'])
                ->where('magasin_id', $validated['magasin_origine_id'])
                ->lockForUpdate()
                ->selectRaw("
                    COALESCE(SUM(
                        CASE WHEN type = 'entree' THEN quantite
                             WHEN type = 'sortie' THEN -quantite
                        END
                    ),0) as stock
                ")
                ->value('stock');

            if ($stockDisponible < $validated['quantite']) {
                throw new \Exception('Quantité demandée supérieure au stock disponible');
            }

            //  Créer le transfert
            $transfert = Transfert::create($validated);

            // Créer le mouvement sortie pour le magasin origine
            Mouvement::create([
                'produit_id' => $validated['produit_id'],
                'magasin_id' => $validated['magasin_origine_id'],
                'type' => Mouvement::TYPE_SORTIE,
                'quantite' => $validated['quantite'],

            ]);

            // Créer le mouvement entrée pour le magasin destination
            Mouvement::create([
                'produit_id' => $validated['produit_id'],
                'magasin_id' => $validated['magasin_destination_id'],
                'type' => Mouvement::TYPE_ENTREE,
                'quantite' => $validated['quantite'],

            ]);
        });

        return redirect()->route('transferts.index')
            ->with('success', 'Transfert de stock créé avec succès');
    }

    /**
     * Display the specified resource.
     */
    public function show(string $id)
    {
        //
    }

    /**
     * Show the form for editing the specified resource.
     */
    public function edit(string $id)
    {
        //
    }

    /**
     * Mise à jour du transfer de stock entre magasin
     */
    public function update(Request $request, string $id)
    {
        $transfert = Transfert::findOrFail(Transfert::keyFromHashId($id));

        if ($transfert->statut == Transfert::STATUT_ANNULE) {
            return redirect()->back()->with('error', 'Le transfert de stock déjà annulé');
        }

        DB::transaction(function () use ($transfert) {

            //Vérifier que le stock destination permet l'annulation du transfert
            $stockDestination = Mouvement::where('produit_id', $transfert->produit_id)
                ->where('magasin_id', $transfert->magasin_destination_id)
                ->lockForUpdate()
                ->selectRaw("
                    COALESCE(SUM(CASE WHEN type = 'entree' THEN quantite WHEN type = 'sortie' THEN -quantite END),0) as stock
                ")
                ->value('stock');

            if ($stockDestination < $transfert->quantite) {
                throw new \Exception('Quantité demandée supérieure au stock disponible');
            }

            // Contre mouvement: retour vers le magasin d'origine
            Mouvement::create([
                'produit_id' => $transfert->produit_id,
                'magasin_id' => $transfert->magasin_origine_id,
                'type' => Mouvement::TYPE_ENTREE,
                'quantite' => $transfert->quantite,
            ]);

            // Contre mouvement: retrait vers le magasin de destination
            Mouvement::create([
                'produit_id' => $transfert->produit_id,
                'magasin_id' => $transfert->magasin_destination_id,
                'type' => Mouvement::TYPE_SORTIE,
                'quantite' => $transfert->quantite,
            ]);

            // Mettre à jour le statut du transfert
            $transfert->update(['statut' => Transfert::STATUT_ANNULE]);
        });

        return redirect()->route('transferts.index')->with('success', 'Transfert de stock annulé avec succès');
    }
}
