<?php
namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models\Link;
use App\Models\Donateur;
use App\Models\Payment;
use App\Enums\LinkStatus;
use App\Enums\PaymentStatus;
use App\Services\NotificationService;
use FedaPay\FedaPay;
use FedaPay\Transaction;
use FedaPay\Customer;
use App\Models\Group;
use Illuminate\Support\Facades\Log;
use Carbon\Carbon;

class DonationController extends Controller
{
    protected NotificationService $notifier;

    public function __construct(NotificationService $notifier)
    {
        $this->notifier = $notifier;
    }
    
    public function showForm(string $campaignSlug, string $token)
    {
        $link = Link::where('token',$token)
            ->whereHas('campaign',fn($q)=>$q->where('slug',$campaignSlug))
            ->firstOrFail();

        return view('donation.showForm', compact('link'));
    }

    public function createTransaction(Request $request, string $campaignSlug, string $token)
    {
        $link = Link::where('token',$token)
            ->whereHas('campaign',fn($q)=>$q->where('slug',$campaignSlug))
            ->firstOrFail();
        
        $data = $request->validate(['amount'=>'required|numeric|min:200']);

        // Init SDK
        FedaPay::setApiKey(config('services.fedapay.secret'));
        FedaPay::setEnvironment(config('services.fedapay.env'));
        
        // Vérifier ou créer le client FedaPay
        $donateur = $link->donateur;
        $donorEmail = $donateur->email;
        if ($donorEmail && !filter_var($donorEmail, FILTER_VALIDATE_EMAIL)) {
            $donateur->update(['email' => null]);
            $donorEmail = null;
        }
        
        try {
            if(!$link->donateur->fedapay_id){
                    // Création de la transaction
                if(!$donorEmail || !$link->donateur->telephone){
                    $transaction = Transaction::create([
                        'description'  => "Don pour {$link->campaign->name}",
                        'amount'       => (int)round($data['amount']),
                        'currency'     => ['iso'=>'XOF'],
                        'callback_url' => route('don.return',[$campaignSlug,$token]),
                    ]);
                }else{
                    $transaction = Transaction::create([
                        'description'  => "Don pour {$link->campaign->name}",
                        'amount'       => (int)round($data['amount']),
                        'currency'     => ['iso'=>'XOF'],
                        'callback_url' => route('don.return',[$campaignSlug,$token]),
                        "customer" => [
                            "firstname" => $link->donateur->prenom,
                            "lastname" => $link->donateur->nom,
                            "email" => $donorEmail,
                            "phone_number" => [
                                "number" => $link->donateur->telephone,
                                "country" => "bj"
                            ]
                        ]
                    ]);
                }
            }else{
                $transaction = Transaction::create([
                    'description'  => "Don pour {$link->campaign->name}",
                    'amount'       => (int)round($data['amount']),
                    'currency'     => ['iso' => 'XOF'],
                    'callback_url' => route('don.return', [$campaignSlug, $token]),
                    'metadata'     => ['link_id' => $link->id],
                    'mode'         => 'mtn_open',
                    'customer'     => ['id' => $link->donateur->fedapay_id],
                ]);
            }
            

            // Générer token et URL
            $tokenObj = $transaction->generateToken();
            $url = $tokenObj->url;

            // Mise à jour du lien
            $link->update([ 'feda_request_id'=>$transaction->id, 'hosted_url'=>$url, 'status'=>LinkStatus::Pending ]);

            return redirect()->away($url);

        } catch (\Exception $e) {
            Log::error('FedaPay transaction error: ' . $e->getMessage());

            $errorMessage = 'Erreur de paiement';
            if (method_exists($e, 'getJsonBody')) {
                $body = $e->getJsonBody();
                $errors = $body['errors'] ?? null;
                if (is_array($errors) && count($errors) > 0) {
                    $firstError = $errors[array_key_first($errors)];
                    if (is_array($firstError) && isset($firstError['message'])) {
                        $errorMessage = $this->translateFedaPayError($firstError['message']);
                    }
                } elseif (isset($body['message'])) {
                    $errorMessage = $this->translateFedaPayError($body['message']);
                }
            }

            return back()->withInput()->with('error', $errorMessage);
        }
    }

    public function checkoutReturn(string $campaignSlug, string $token, Request $request)
    {
        $link = Link::where('token',$token)
            ->whereHas('campaign', fn($q)=>$q->where('slug',$campaignSlug))
            ->firstOrFail();

        $status = $request->query('status');
        $fedapayId = $request->query('id');
        
        if ($status === 'approved') {
            try {         
                $message = "Merci, votre don a été confirmé avec succès !";
                // Send thank you notification
                FedaPay::setApiKey(config('services.fedapay.secret'));
                FedaPay::setEnvironment(config('services.fedapay.env'));
                $tx = Transaction::retrieve($fedapayId);
                if (isset($tx->customer) && isset($tx->customer->email)) {
                    $newEmail = trim($tx->customer->email);
                    if (filter_var($newEmail, FILTER_VALIDATE_EMAIL)) {
                        $current = $link->donateur->email;
                        if (!$current || !filter_var($current, FILTER_VALIDATE_EMAIL)) {
                            $link->donateur->update(['email' => $newEmail]);
                        }
                    }
                }
                // Création du paiement en base
                //dd($tx);
                Payment::create([
                    'link_id'        => $link->id,
                    'feda_payment_id'=> $tx->id,
                    'amount'         => (int) round($tx->amount),
                    'currency'       => "XOF",
                    'status'         => PaymentStatus::Paid,
                    'paid_at'        => Carbon::parse($tx->created_at)->format('Y-m-d H:i:s'),
                ]);
            
                // Mise à jour des groupes
                $campaign     = $link->campaign;
                $waitingGroup = Group::where('name', "{$campaign->name} - En attente")->first();
                $paidGroup    = Group::where('name', "{$campaign->name} - Payés")->first();

                if ($waitingGroup) {
                    $waitingGroup->donateurs()->detach($link->donateur_id);
                }
                if ($paidGroup) {
                    $paidGroup->donateurs()->syncWithoutDetaching([$link->donateur_id]);
                }
                
                $link->update([ 'status'=>LinkStatus::Paid ]);
                $this->notifier->sendThank($status, $link);
            } catch (\Exception $e) {
                Log::error('FedaPay retrieve error: ' . $e->getMessage());
            }

            
                
        } elseif ($status === 'canceled') {
            $message = "Votre paiement a été annulé. Si vous le souhaitez, vous pouvez réessayer plus tard.";
            // Notify cancellation
            $link->status == LinkStatus::Paid ? $link->update([ 'status'=>LinkStatus::Paid ]) : $link->update([ 'status'=>LinkStatus::Failed ]);

            $this->notifier->sendThank($status, $link);
        }
        elseif ($status === 'pending') {
                $message = "Vous etes en attente de paiement. Si vous le souhaitez, vous pouvez réessayer plus tard.";
                // Notify cancellation
                $link->status == LinkStatus::Paid ? $link->update([ 'status'=>LinkStatus::Paid ]) : $link->update([ 'status'=>LinkStatus::Pending ]);
                $this->notifier->sendThank($status, $link);
        }  elseif ($status === 'failed') {
            $message = "Votre transaction a échoué. Si vous le souhaitez, vous pouvez réessayer plus tard.";
            // Notify cancellation
            $link->status == LinkStatus::Paid ? $link->update([ 'status'=>LinkStatus::Paid ]) : $link->update([ 'status'=>LinkStatus::Failed ]);

            $this->notifier->sendThank($status, $link);
        } else {
            $message = "Statut de paiement inconnu. Veuillez vérifier ultérieurement.";
        }

        return view('donation.thankyou', compact('link','status','message'));
    }

    public function manualTransaction(Request $request, Link $link)
    {
        $data = $request->validate([
            'transaction_id' => 'required|string',
        ]);

        try {
            FedaPay::setApiKey(config('services.fedapay.secret'));
            FedaPay::setEnvironment(config('services.fedapay.env'));

            $tx = Transaction::retrieve($data['transaction_id']);
            if (isset($tx->customer) && isset($tx->customer->email)) {
                $newEmail = trim($tx->customer->email);
                if (filter_var($newEmail, FILTER_VALIDATE_EMAIL)) {
                    $current = $link->donateur->email;
                    if (!$current || !filter_var($current, FILTER_VALIDATE_EMAIL)) {
                        $link->donateur->update(['email' => $newEmail]);
                    }
                }
            }

            Payment::firstOrCreate(
                ['feda_payment_id' => $tx->id],
                [
                    'link_id' => $link->id,
                    'amount'  => (int) round($tx->amount),
                    'currency' => 'XOF',
                    'status'   => PaymentStatus::Paid,
                    'paid_at'  => Carbon::parse($tx->created_at)->format('Y-m-d H:i:s'),
                ]
            );

            $campaign = $link->campaign;
            $waitingGroup = Group::where('name', "{$campaign->name} - En attente")->first();
            $paidGroup = Group::where('name', "{$campaign->name} - Payés")->first();

            if ($waitingGroup) {
                $waitingGroup->donateurs()->detach($link->donateur_id);
            }
            if ($paidGroup) {
                $paidGroup->donateurs()->syncWithoutDetaching([$link->donateur_id]);
            }

            $link->update(['status' => LinkStatus::Paid]);

            return back()->with('success', 'Transaction enregistrée.');
        } catch (\Exception $e) {
            Log::error('Manual transaction error: ' . $e->getMessage());
            return back()->with('error', 'Erreur lors de la récupération de la transaction.');
        }
    }

    private function translateFedaPayError(string $message): string
    {
        $msg = strtolower($message);

        if (str_contains($msg, 'invalid email') || str_contains($msg, 'email invalide') || str_contains($msg, 'invalid_email')) {
            return 'Adresse e-mail invalide.';
        }

        if (str_contains($msg, 'invalid phone') || str_contains($msg, 'phone number') || str_contains($msg, 'invalid_phone')) {
            return 'Numéro de téléphone invalide.';
        }

        if (str_contains($msg, 'insufficient') || str_contains($msg, 'insufficient amount')) {
            return 'Montant insuffisant.';
        }

        if (str_contains($msg, 'amount') || str_contains($msg, 'montant')) {
            return 'Montant invalide.';
        }

        return 'Erreur de paiement';
    }

    public function findCustomerByEmailAndPhone(string $email)
    {
        $all = Customer::all();
        $customers = $all->customers;
        
        $matching = null;
        foreach ($customers as $cust) {
            // on s’assure qu’on a bien un objet et qu’il définit email
            if (is_object($cust) && isset($cust->email)
                && strcasecmp($cust->email, $email) === 0
            ) {
                $matching = $cust;
                break;
            }
        }

        if ($matching) {
            // trouvé !
            
            return $matching;
        }
        return null;
    }
}
