<?php

namespace App\Http\Controllers;

use App\Models\Caution;
use App\Models\Client;
use Barryvdh\DomPDF\Facade\Pdf;
use Carbon\Carbon;
use Illuminate\Http\Request;

class ClientController extends Controller
{
    /**
     * Liste des clients.
     */
    public function index()
    {
        $clients = Client::latest()->paginate(10);

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

    /**
     * Détails d'un client.
     */
    public function show(string $id)
    {
        $client = Client::with(['ventes.produit', 'ventes.magasin'])
            ->findOrFail(Client::keyFromHashId($id));

        return view('clients.show', compact('client'));
    }

    /**
     * Relevé de compte client (tous achats et paiements) en PDF.
     */
    public function relevePdf(string $id)
    {
        $client = Client::with([
            'ventes' => fn($q) => $q->with(['produit', 'magasin', 'paiements']),
            'cautions',
        ])->findOrFail(Client::keyFromHashId($id));

        // Uniquement les ventes de ce client (relation client -> ventes)
        $ventes = $client->ventes;
        // Solde d'ouverture = somme des montants restants dans la table cautions (varie avec les prélèvements sur achats)
        $soldeOuverture = (float) $client->cautions->sum('montant');
        $totalFactures = $ventes->sum('montant');
        $totalPaye = 0;
        $transactions = [];

        $tousPaiements = $ventes->pluck('paiements')->flatten();
        $toutesDates = $ventes->pluck('date_vente')->filter()->merge(
            $tousPaiements->pluck('date_paiement')->filter()
        );
        $dateDebut = $toutesDates->isNotEmpty() ? Carbon::parse($toutesDates->min()) : now();
        $dateFin = $toutesDates->isNotEmpty() ? Carbon::parse($toutesDates->max()) : now();

        foreach ($ventes as $vente) {
            $totalPaye += $vente->paiements->sum('montant_paye');
        }

        // Construire la liste chronologique : factures + paiements
        foreach ($ventes as $vente) {
            $transactions[] = [
                'date' => $vente->date_vente,
                'reference' => $vente->reference,
                'type' => 'Facture',
                'debit' => (float) $vente->montant,
                'credit' => 0,
                'solde' => null,
                'mode_paiement' => null,
                'remarques' => $vente->produit?->designation ?? '—',
            ];
        }
        foreach ($ventes as $vente) {
            foreach ($vente->paiements as $paiement) {
                $transactions[] = [
                    'date' => $paiement->date_paiement ?? $paiement->created_at,
                    'reference' => $paiement->reference ?? '—',
                    'type' => 'Paiement',
                    'debit' => 0,
                    'credit' => (float) $paiement->montant_paye,
                    'solde' => null,
                    'mode_paiement' => $paiement->mode_paiement ?? '—',
                    'remarques' => null,
                ];
            }
        }

        usort($transactions, function ($a, $b) {
            $d1 = $a['date'] instanceof \Carbon\Carbon ? $a['date'] : Carbon::parse($a['date']);
            $d2 = $b['date'] instanceof \Carbon\Carbon ? $b['date'] : Carbon::parse($b['date']);
            return $d1->getTimestamp() <=> $d2->getTimestamp();
        });

        // Solde courant : partir du solde d'ouverture (caution), puis appliquer chaque opération
        $soldeCourant = $soldeOuverture;
        foreach ($transactions as &$row) {
            $soldeCourant += $row['debit'] - $row['credit'];
            $row['solde'] = $soldeCourant;
        }
        unset($row);

        // Insérer la ligne "Solde d'ouverture" (caution du client) en première position
        if (! empty($transactions)) {
            array_unshift($transactions, [
                'date' => $dateDebut,
                'reference' => '—',
                'type' => 'Solde d\'ouverture',
                'debit' => $soldeOuverture,
                'credit' => 0,
                'solde' => $soldeOuverture,
                'mode_paiement' => null,
                'remarques' => 'Caution client',
            ]);
        } else {
            // Aucune vente : afficher uniquement le solde d'ouverture si caution > 0
            if ($soldeOuverture > 0) {
                $transactions[] = [
                    'date' => $dateDebut,
                    'reference' => '—',
                    'type' => 'Solde d\'ouverture',
                    'debit' => $soldeOuverture,
                    'credit' => 0,
                    'solde' => $soldeOuverture,
                    'mode_paiement' => null,
                    'remarques' => 'Caution client',
                ];
            }
        }

        $soldeDu = $soldeOuverture + $totalFactures - $totalPaye;
        // Solde anticipé = avance du client quand il a payé plus qu'il ne doit (ex. partiellement payé sur plusieurs factures puis paiement global)
        $soldeAnticipe = $soldeDu < 0 ? (float) abs($soldeDu) : 0.0;
        $soldeDuAffichage = $soldeDu > 0 ? $soldeDu : 0.0;

        // Résumé des statuts de caution : si montant <= 0 on affiche "Solde épuisé" même si le statut en base est encore "active"
        $cautionStatutsResume = $client->cautions
            ->map(function ($caution) {
                $statutAffichage = (float) $caution->montant <= 0
                    ? \App\Models\Caution::STATUT_EPUISE
                    : $caution->statut;
                return $statutAffichage;
            })
            ->groupBy(fn($s) => $s)
            ->map(function ($group) {
                return \App\Models\Caution::libelleStatut($group->first())
                    . ($group->count() > 1 ? ' (' . $group->count() . ')' : '');
            })
            ->values()
            ->implode(', ');

        $pdf = Pdf::loadView('clients.releve-pdf', [
            'client' => $client,
            'cautionStatutsResume' => $cautionStatutsResume ?: null,
            'transactions' => $transactions,
            'soldeOuverture' => $soldeOuverture,
            'totalFactures' => $totalFactures,
            'totalPaye' => $totalPaye,
            'soldeAnticipe' => $soldeAnticipe,
            'soldeDu' => $soldeDuAffichage,
            'dateDebut' => $dateDebut,
            'dateFin' => $dateFin,
        ])->setPaper('a4');

        return $pdf->stream('releve-compte-' . \Illuminate\Support\Str::slug($client->nom) . '.pdf');
    }



    /**
     * Enregistrement d'un nouveau client
     */
    public function store(Request $request)
    {
        $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);

        //Créons une caution pour le client
        Caution::create([
            'client_id' => $client->id,
            'montant' => $validated['caution'],
            'date_depot' => now(),
            'statut' => Caution::STATUT_ACTIVE,
        ]);

        return redirect()->route('clients.index')->with('success', 'Client créé avec succès');
    }

    /**
     * Mise à jour des informations du client
     */
    public function update(Request $request, string $id)
    {
        $validated = $request->validate([
            'nom' => 'required|string|max:255',
            'telephone' => 'required|string|min:10',
            'adresse' => 'nullable|string|max:150',
            'caution' => 'required|numeric|min:0',
        ]);

        //Vérifie si le client existe
        $client = Client::findOrFail(Client::keyFromHashId($id));
        //Met à jour les informations du client
        $client->update($validated);

        //Mise à jour de la caution du client
        $client->cautions()->update([
            'montant' => $validated['caution'],
            'updated_at' => now(),
        ]);

        return redirect()->route('clients.index')->with('success', 'Client mis à jour avec succès');
    }

    /**
     * Suppression du client
     */
    public function destroy(string $id)
    {
        //Vérifie si le client existe
        $client = Client::findOrFail(Client::keyFromHashId($id));
        //Suppression du client
        $client->delete();
        // $client->update([
        //     'deleted_at' => now()
        // ]);
        return redirect()->route('clients.index')->with('success', 'Client supprimé avec succès');
    }
}