<?php

namespace App\Http\Controllers;

use App\Exports\TransfertsExport;
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;
use Maatwebsite\Excel\Facades\Excel;

class TransfertStockController extends Controller
{
    /**
     * Liste des transfert de stock entre magasin
     */
    public function index(Request $request)
    {
        $query = Transfert::with(['magasinOrigine', 'magasinDestination', 'produit']);

        // Filtre par date (du / au)
        if ($request->filled('date_from')) {
            $query->whereDate('date_transfert', '>=', $request->date_from);
        }
        if ($request->filled('date_to')) {
            $query->whereDate('date_transfert', '<=', $request->date_to);
        }

        // Filtre par magasin d'origine
        if ($request->filled('magasin_origine_id')) {
            $query->where('magasin_origine_id', $request->magasin_origine_id);
        }

        // Filtre par magasin destination
        if ($request->filled('magasin_destination_id')) {
            $query->where('magasin_destination_id', $request->magasin_destination_id);
        }

        // Filtre par produit
        if ($request->filled('produit_id')) {
            $query->where('produit_id', $request->produit_id);
        }

        // Filtre par statut
        if ($request->filled('statut') && in_array($request->statut, [Transfert::STATUT_EXPEDIE, Transfert::STATUT_ANNULE])) {
            $query->where('statut', $request->statut);
        }

        $transferts = $query->latest('date_transfert')->paginate(15)->withQueryString();

        // Stock actuel restant dans le magasin d'origine pour chaque transfert
        $transferts->each(function ($t) {
            $t->stock_actuel_origine = (int) Mouvement::where('produit_id', $t->produit_id)
                ->where('magasin_id', $t->magasin_origine_id)
                ->selectRaw("COALESCE(SUM(CASE WHEN type = 'entree' THEN quantite WHEN type = 'sortie' THEN -quantite END), 0) as stock")
                ->value('stock');
        });

        $magasins = Magasin::orderBy('nom')->get(['id', 'nom']);
        $produits = Produit::orderBy('designation')->get(['id', 'designation', 'reference']);

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

    /**
     * Exporte les transferts en XLSX selon les filtres appliqués.
     */
    public function export(Request $request)
    {
        $query = Transfert::with(['magasinOrigine', 'magasinDestination', 'produit']);

        if ($request->filled('date_from')) {
            $query->whereDate('date_transfert', '>=', $request->date_from);
        }
        if ($request->filled('date_to')) {
            $query->whereDate('date_transfert', '<=', $request->date_to);
        }
        if ($request->filled('magasin_origine_id')) {
            $query->where('magasin_origine_id', $request->magasin_origine_id);
        }
        if ($request->filled('magasin_destination_id')) {
            $query->where('magasin_destination_id', $request->magasin_destination_id);
        }
        if ($request->filled('produit_id')) {
            $query->where('produit_id', $request->produit_id);
        }
        if ($request->filled('statut') && in_array($request->statut, [Transfert::STATUT_EXPEDIE, Transfert::STATUT_ANNULE])) {
            $query->where('statut', $request->statut);
        }

        $transferts = $query->latest('date_transfert')->get();

        $filename = 'transferts_' . now()->format('Y-m-d_H-i') . '.xlsx';

        return Excel::download(new TransfertsExport($transferts), $filename);
    }

    /**
     * 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');
        }

        return 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']) {
                return redirect()->back()->with('error', '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'],

            ]);

            /**
             * Mettre à jour le stock du produit dans le magasin d'origine
             */
            Stock::where('produit_id', $validated['produit_id'])
                ->where('magasin_id', $validated['magasin_origine_id'])
                ->decrement('quantite', $validated['quantite']);

            /**
             * Mettre à jour le stock du produit dans le magasin de destination
             * increment('quantite') : incrémente la quantité
             * decrement('quantite') : décrémente la quantité
             * stockDestination : stock actuel dans le magasin de destination
             * firstOrCreate() : crée un stock si il n'existe pas
             */

            $stockDestination = Stock::firstOrCreate(
                [
                    'produit_id' => $validated['produit_id'],
                    'magasin_id' => $validated['magasin_destination_id'],
                ],
                ['quantite' => Stock::QUANTITE_DEFAULT, 'seuil_alerte' => Stock::SEUIL_ALERTE_DEFAULT]
            );
            $stockDestination->increment('quantite', $validated['quantite']);

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

    /**
     * Annulation d'un transfert de stock entre magasin
     * Avant l'annulation, on vérifie que le stock destination permet l'annulation du transfert
     * On crée les contre mouvements: retour vers le magasin d'origine et retrait vers le magasin de destination
     * On met à jour le statut du transfert
     * On retourne vers la page de liste des transferts avec un message de succès
     * Si une erreur survient, on retourne vers la page de liste des transferts avec un message d'erreur
     * Mise à jour du transfer de stock entre magasin
     */
    public function update(Request $request, string $id)
    {
        $transfert = Transfert::findOrFail(Transfert::keyFromHashId($id));
        $this->authorizeVendeurOwnership($transfert);

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

        return 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) {
                return redirect()->back()->with('error', '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 stock du produit dans le magasin d'origine
             * increment('quantite') : incrémente la quantité
             */
            Stock::where('produit_id', $transfert->produit_id)
                ->where('magasin_id', $transfert->magasin_origine_id)
                ->increment('quantite', $transfert->quantite);

            /**
             * Mettre à jour le stock du produit dans le magasin de destination
             * decrement('quantite') : décrémente la quantité
             */
            Stock::where('produit_id', $transfert->produit_id)
                ->where('magasin_id', $transfert->magasin_destination_id)
                ->decrement('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');
        });
    }
}
