<?php

namespace App\Http\Controllers;

use App\Exports\VentesExport;
use App\Models\Caution;
use App\Models\Client;
use App\Models\Creance;
use App\Models\Magasin;
use App\Models\Mouvement;
use App\Models\Paiement;
use App\Models\Produit;
use App\Models\Stock;
use App\Models\Vente;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Maatwebsite\Excel\Facades\Excel;

class VenteController extends Controller
{
    /**
     * Liste des ventes de produit
     */
    public function index(Request $request)
    {
        $query = $this->buildFilteredQuery($request);

        $ventes = $query
            ->latest('date_vente')
            ->paginate(10)
            ->withQueryString();

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

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

    /**
     * Export XLSX des ventes en fonction des filtres.
     */
    public function export(Request $request)
    {
        $ventes = $this->buildFilteredQuery($request)
            ->latest('date_vente')
            ->get();

        $filename = 'ventes';

        if ($request->filled('date_debut')) {
            $filename .= '_from_' . $request->date('date_debut')->format('Y-m-d');
        }
        if ($request->filled('date_fin')) {
            $filename .= '_to_' . $request->date('date_fin')->format('Y-m-d');
        }
        if ($request->filled('statut_paiement')) {
            $filename .= '_' . $request->input('statut_paiement');
        }

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

        return Excel::download(new VentesExport($ventes), $filename);
    }

    /**
     * Construit la requête des ventes avec les filtres communs.
     */
    protected function buildFilteredQuery(Request $request)
    {
        $query = Vente::with(['client', 'produit', 'magasin', 'creance', 'paiement']);

        if ($request->filled('date_debut') && $request->filled('date_fin')) {
            $query->whereBetween('date_vente', [
                $request->date('date_debut'),
                $request->date('date_fin'),
            ]);
        } elseif ($request->filled('date_debut')) {
            $query->whereDate('date_vente', '>=', $request->date('date_debut'));
        } elseif ($request->filled('date_fin')) {
            $query->whereDate('date_vente', '<=', $request->date('date_fin'));
        }

        if ($request->filled('statut_paiement')) {
            $query->where('statut_paiement', $request->input('statut_paiement'));
        }

        return $query;
    }

    /**
     * Ajouter une vente de produit.
     */
    public function store(Request $request)
    {
        $validated = $request->validate([
            'client_id' => 'required|exists:clients,id',
            'produit_id' => 'required|exists:produits,id',
            'magasin_id' => 'required|exists:magasins,id',
            'quantite' => 'required|integer|min:1',
            'montant' => 'required|numeric|min:0',
            'mode_paiement' => 'nullable|string|max:50',
            'statut_paiement' => 'required|in:en_attente,partiellement,paye',
            'montant_paye' => 'nullable|numeric|min:0',
        ]);


        $validated['date_vente'] = now()->toDateString();

        $validated['montant_paye'] = match ($validated['statut_paiement']) {
            'paye' => $validated['montant'],
            'partiellement' => (float) ($validated['montant_paye'] ?? 0),
            default => 0,
        };

        try {

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

                // 1️⃣ Vérification du stock
                $stockDisponible = Mouvement::stockActuel(
                    (int) $validated['produit_id'],
                    (int) $validated['magasin_id']
                );

                if ($stockDisponible < $validated['quantite']) {
                    throw new \Exception('Stock insuffisant.');
                }

                // 2️⃣ Logique caution / montant restant
                $montantVente       = (float) $validated['montant'];
                $cautionDisponible  = (float) Caution::where('client_id', $validated['client_id'])
                    //->where('statut', Caution::STATUT_ACTIVE)
                    ->sum('montant');

                $montantPreleve     = min($cautionDisponible, $montantVente);
                $montantRestant     = $montantVente - $montantPreleve;

                $validated['montant_paye'] = $montantPreleve;

                if ($montantRestant == 0) {
                    $validated['statut_paiement'] = Vente::STATUT_PAYE;
                } elseif ($montantPreleve > 0) {
                    $validated['statut_paiement'] = Vente::STATUT_PARTIELLEMENT;
                } else {
                    $validated['statut_paiement'] = Vente::STATUT_EN_ATTENTE;
                }


                //Retirer les champs qui n'existent pas en base
                unset($validated['mode_paiement'], $validated['montant_paye']);

                dd($validated['mode_paiement']);
                // 3️⃣ Créer la vente
                $vente = Vente::create($validated);

                // 4️⃣ Décrémenter la caution de manière sécurisée
                if ($montantPreleve > 0) {
                    $cautions = Caution::where('client_id', $validated['client_id'])
                        // ->where('statut', Caution::STATUT_ACTIVE)
                        ->lockForUpdate()
                        ->get();

                    $restePreleve = $montantPreleve;

                    foreach ($cautions as $caution) {
                        $deduit = min($caution->montant, $restePreleve);
                        $caution->decrement('montant', $deduit);
                        //Déduction du montant prélevé de la caution
                        $restePreleve -= $deduit;

                        //Nouvelle logique : mettre le statut à épuisé si le montant = 0
                        if ($caution->fresh()->montant <= 0) {
                            $caution->update(['statut' => Caution::STATUT_EPUISE]); // ou un autre statut que tu as défini
                        }

                        //Si le montant restant à prélever est inférieur ou égal à 0, on arrête la boucle
                        if ($restePreleve <= 0) {
                            break;
                        }
                    }
                }

                // 5️⃣ Historiser le paiement initial si prélèvement > 0
                if ($montantPreleve > 0) {
                    Paiement::create([
                        'vente_id'      => $vente->id,
                        'montant'       => $montantPreleve,
                        'mode_paiement' => $validated['mode_paiement'],
                        'date_paiement' => now()->toDateString(),
                        'user_id' => Auth::id()
                    ]);
                }

                // 6️⃣ Créer la créance pour le montant restant
                if ($montantRestant > 0) {
                    Creance::create([
                        'client_id'       => $vente->client_id,
                        'vente_id'        => $vente->id,
                        'montant_initial' => $vente->montant,
                        'montant_restant' => $montantRestant,
                        'statut'          => 'impaye',
                        'date_creance'    => now()->toDateString(),
                        'user_id' => Auth::id(),
                    ]);
                }

                // 7️⃣ Créer le mouvement de sortie du stock
                Mouvement::create([
                    'produit_id' => $validated['produit_id'],
                    'magasin_id' => $validated['magasin_id'],
                    'type'       => Mouvement::TYPE_SORTIE,
                    'quantite'   => $validated['quantite'],
                ]);

                // 8️⃣ Mise à jour du stock agrégé
                Stock::where('produit_id', $validated['produit_id'])
                    ->where('magasin_id', $validated['magasin_id'])
                    ->decrement('quantite', $validated['quantite']);
            });

            return redirect()->route('ventes.index')
                ->with('success', 'Vente créée avec succès');
        } catch (\Exception $e) {
            return redirect()->back()
                ->with('error', $e->getMessage())
                ->withInput();
        }
    }

    /**
     * Créer un client depuis le formulaire de vente (AJAX).
     */
    public function storeClient(Request $request): JsonResponse
    {
        $validated = $request->validate([
            'nom' => 'required|string|max:255',
            'telephone' => 'required|string|min:10',
            'adresse' => 'nullable|string|max:150',
            'caution' => 'required|numeric|min:0',
        ]);

        $client = Client::create($validated);

        Caution::create([
            'client_id' => $client->id,
            'montant' => $validated['caution'],
            'date_depot' => now(),
            'statut' => Caution::STATUT_ACTIVE,
        ]);

        return response()->json([
            'id' => $client->id,
            'nom' => $client->nom,
            'value' => $client->id,
            'label' => $client->nom,
        ]);
    }

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

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

    /**
     * Update the specified resource in storage.
     */
    public function update(Request $request, string $id)
    {
        //
    }

    /**
     * Suppression d'une vente
     */
    public function destroy(string $id) {}
}