<?php

namespace App\Console\Commands\PaymentTransactions;

use App\Models\PaymentManagement\Payment;
use App\Models\PaymentManagement\PaymentTransaction;
use App\Models\SettingManagement\PaymentTransactionStatus;
use App\Services\MobileMoney\MakeAMobileMoney;
use Illuminate\Console\Command;


class CheckAndValidateTransactions extends Command{
    use MakeAMobileMoney;

    protected $signature = 'payments-transactions:check-and-validate';
    protected $description = "Check le statut de toutes les transactions qui se trouvent
        dans la table 'transaction' et les valide si l'api a repondu success";


    /** change le statut des transactions en cours de traitement
     *
     */
    public function changeStatus(){
        $transactions = PaymentTransaction::where('status_code',PaymentTransactionStatus::UNDER_PROCESS)->get();

        $this->info(__("Process de changement de statut... (:count transactions)",
            ["count" => format_amount(count($transactions)) ]));

        /*s'il ya des transactions*/
        if (!blank($transactions)){
            $i = 1 ;

            foreach ($transactions as $transaction) :
                $workout_at = date_format($transaction->workout_at,'Y-m-d H:i:s');

               if ($workout_at){
                   //date du crone -15min
                   $time_change_status = date('Y-m-d H:i:s',strtotime("-5minutes"));
                   if ($workout_at < $time_change_status){
                       $transaction->update(['status_code' => PaymentTransactionStatus::UNPROCESSED]);
                   }
               }
                $this->info("Passage $i");
                $i++;
            endforeach;
        }
    }

    public function handle(){

        $dir_log = '/transactions/check-statuses/';
        $transactions = PaymentTransaction::where('status_code',PaymentTransactionStatus::UNPROCESSED)->get();
        $momoConfig = config('mobile-money');
        $paymentResult['errors'] = null;

        $this->info(__(":count transactions trouvées",['count' => format_amount(count($transactions))]));

        $nbre_tours = 1 ;

        //dd($transactions->pluck('reference'));
        /* s'il ya des transactions à traité */
        if (!blank($transactions)){

            set_time_limit(600); // 10 min
            foreach ($transactions as $transaction) : // pour chaque transaction
                $paymentResult = null;
                $paymentMethodCode = $transaction->paymentMethod->code; // "mtn-momo-cmr"
                $apiTransactionStatus = null;

                $dirLogError = $dir_log.$paymentMethodCode."/errors";
                $dirLorSuccess = $dir_log.$paymentMethodCode."/success";
                $order = $transaction->order ;  /*récupère la commande qui a été payé*/

                /*recupere la référence de la transaction*/
                $transactionReference = $transaction->reference;
                /*variable pour les données de paiement*/
                $paymentDatas = null;

                try {
                    /*check le statut de la transaction sur l'api*/
                    $apiTransactionStatus = $this->getTransactionStatus($transaction);
                    $message = "tour = ".format_amount($nbre_tours).'| reference = '.$transactionReference."| method = ".$paymentMethodCode;
                    $this->info($message);
                   // write_log($log_dir_success,$message,'info',$paymentMethodCode);

                }catch (\Exception $exception){
                    $this->info(format_exception_message($exception));
                    write_log($dirLogError,$exception,'error',$paymentMethodCode);
                    $transaction->update(['exception' => format_exception_message($exception)]);
                }
                finally {
                    try {
                        $newStatus = null;
                        $saveOrder = false;
                        if (!blank($apiTransactionStatus)){
                            $payer = $transaction->payer; // le payeur
                            $paymentDatas['saved_by_cron'] = true;

                            //check le statut de la transaction , et enregistre le Payment en cas de succès
                            $resultCheckStatus = $this->checkTransactionStatus($apiTransactionStatus,$transaction, $paymentDatas);
                            $paymentResult = $resultCheckStatus;
                            if (isset($resultCheckStatus['transaction']) ){

                                /*si la transaction a été approuvé*/
                                if ($resultCheckStatus['transaction']['success']){
                                    $successReference = $resultCheckStatus['transaction']['reference'] ?? "";

                                    if (!empty($successReference)){
                                        $transaction->update(['success_reference' => $successReference]);
                                    }

                                    /*si le payeur existe et l'api a retourné une reference*/
                                    if ($payer and !empty($successReference)){

                                        /*recupere paiement */
                                        $payment = Payment::findByReference($successReference);

                                        if ($payment instanceof Payment){
                                            /*si le paiement n'est pas utilisé*/
                                            if (!blank($payment) and !$payment->is_used){
                                                $saveOrder = true;
                                            }
                                            else{
                                                $ordersUsedId = implode(";",$payment->usages->pluck('usageable_id')->toArray());
                                                $message = __("Le paiement est déjà utilisé sur: (:ids)",['ids' => $ordersUsedId]);
                                                $paymentResult['payment']["error"] = $message;
                                                write_log($dirLogError,$message,'error',$paymentMethodCode);
                                            }
                                        }

                                    }else{
                                        $message  = __("Informations du payeur manquantes pour enregistrer le paiement");
                                        $paymentResult['errors'][]  = $message;
                                        write_log($dirLogError,$message,'error',$paymentMethodCode);
                                    }
                                }
                            }
                        }
                        else{
                            $message = __("Aucune reponse.");
                            $paymentResult['errors'][] = $message;
                            write_log($dirLogError,$message,'error',$paymentMethodCode);
                        }
                        if (!empty($message)){
                            $this->info($message);
                        }
                    }
                    catch (\Exception $exception){
                        write_log($dirLogError,$exception,'error',$paymentMethodCode);
                        $transaction->update(['exception' => format_exception_message($exception)]);
                    }
                    finally {
                        $workout_at = format_date( $transaction->workout_at,'Y-m-d H:i');
                        //date du crone -15min
                        $time_change_status = date('Y-m-d H:i',strtotime("-15minutes"));


                        //Si la tranasaction a déja fait plus de 15min
                        if ($workout_at < $time_change_status){
                            //Echec
                           // $transaction->update(['status_code' => $newStatus->id]);
                        }

                       // dd($workout_at ,$time_change_status,($workout_at < $time_change_status),$saveOrder);
                        if ($saveOrder){

                            $saveOrderClasses = $momoConfig['save-order-when-cron-check-transaction-status'] ?? [];
                            if (!empty($saveOrderClasses)){
                                if (is_array($saveOrderClasses)){
                                    foreach ($saveOrderClasses as $saveOrderClass) {
                                        $callable = new $saveOrderClass;
                                        $callable($transaction);
                                    }
                                }else{
                                    new $saveOrderClasses($transaction);
                                }
                            }else{
                                $message = __("les informations de commande sont manquantes pour la transaction ':ref'",['ref' => $transactionReference]);
                                write_log($dirLogError,$message,'error',$paymentMethodCode);
                                $paymentResult['errors'][] = $message;
                            }
                        }
                        /*s'il ya de message d'erreur lors des verifications*/
                        if (!empty($paymentResult)){
                            $transaction->update(['payment_result' => $paymentResult]);
                        }
                        else{
                            $message = __("Opération réussie, aucune erreur détectée lors des verifications");
                            $paymentResult["success"] = $message;
                            write_log($dirLorSuccess,$message,'info',$paymentMethodCode);
                        }
                    }
                }
                $nbre_tours++;
            endforeach;
            $message = __("nbre lignes a vérifier = :transactions ; nbre de passages cron = :tours",
                     ['transactions' => format_amount(count($transactions)),'tours' => format_amount($nbre_tours)]);
            $this->info($message);
        }else{
            $message  = __("Aucune transaction à vérifier");
            $this->info($message);
        }

        $this->changeStatus();

        // Artisan::call("queue:work --queue=default,rapports --tries=3 --stop-when-empty");
    }
}
