<?php

use App\Exceptions\NewIdCannotGeneratedException;
use App\Models\LocalizationManagement\Country;
use App\Models\OrderManagement\Order;
use App\Models\UserManagement\Customer;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;
use Monolog\Handler\RotatingFileHandler;
use Monolog\Logger;
use Stevebauman\Location\Facades\Location;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Support\Facades\File;

if (!function_exists('callApi')) {
    /**Create API query and execute a GET/POST request
     * @param string $httpMethod GET/POST
     * @param string $endpoint
     * @param array $options
     * @return mixed
     * @throws GuzzleException
     */
    function callApi($httpMethod = "post", $endpoint = "", $options = []){
        $client = new Client(['verify' => app()->environment() != "local"]);
        // POST method or GET method
        try {
            $response = $client->request(strtoupper($httpMethod),$endpoint,$options);
            return json_decode($response->getBody()->getContents(),true);
        }catch (\Exception $exception){
            write_log("call-api",$exception,"error",$endpoint);
        }
    }
}

if (!function_exists('format_amount')) {
    function format_amount($numba ,$devise = "",$separateur = " ")  {
        if(isset($devise) and is_bool($devise) and $devise == true){
            $devise = getSettingsOf("currency");
        }
        if (!empty($devise)){
            $devise = " ".$devise;
        }
        return number_format(ceil($numba),0,".",$separateur).$devise ;
    }
}

if(!function_exists("selected_country")){
    function selected_country(){
        $countryName = user_location()['countryName'] ?? "Cameroon";
        return Country::findByName($countryName);
    }
}

if (! function_exists('user_location')) {
    /** retourne les données de localisation de l'user
     * @return  array
     * @throws Exception
     */
    function user_location(){
        $ip = (app()->isLocal()) ? '154.72.168.247' : request()->ip();
        $location = [];
        try {
            $location = Location::get($ip);
            if ($location){
                $location = $location->toArray();
            }
        }catch (Exception $exception){}
        return $location;
    }
}


if (! function_exists('format_with_char')) {
    function format_with_char($value,$limit = 5,$added_char = "0",$before = true){
        $value = (string) $value;
        $lenght_value = strlen($value);
        $zero = "";
        if ($lenght_value < $limit){
            for ($i = 1 ; $i <= ($limit - $lenght_value) ; $i++){
                $zero.= $added_char;
            }
        }
        return (string) ($before) ? $zero.$value:$value.$zero;
    }
}

if (! function_exists('format_exception_message')) {
    function format_exception_message($exception){
        return $exception->getMessage()." file = ".$exception->getFile()."| line = ".$exception->getLine()."| trace = ".$exception->getTraceAsString();
    }
}

if (!function_exists('write_log')) {
    function write_log($directory,$message,$type = 'info',$name = "action"){

        if ($message instanceof Exception){
            $message = format_exception_message($message);
        }

        if (is_array($message) or is_object($message)){
            $message = json_encode($message);
        }

        if (blank($directory) or blank($name)){
            if (!empty($message)) {
                Log::error($message);
            }
        }else{
            $logger = new Logger(Str::Slug($name));
            /*fichier journal qui sera crée de journal d'erreur*/
            $log_file = storage_path()."/logs/$directory/log.log";

            /*Génération de journal d'erreur*/
            $logger = $logger->pushHandler(new RotatingFileHandler($log_file));

            if ($type != "info"){
                $logger->error($message);
            }else{
                $logger->info($message);
            }

            if ($directory){
                $files= File::allFiles(storage_path("logs/$directory"));
                $deletable = env("LOG_FILE_DELETED_AFTER","-3days");
                foreach ($files as $file) {
                    $path = $file->getRealPath();
                    $lastModified = File::lastModified($path);
                    $lastModified = date('Y-m-d',$lastModified);
                    $deletable_date = date("Y-m-d",strtotime($deletable));
                   // echo ("path= $path; lastModified = $lastModified ; deletableDate = $deletable_date ; deletable = $deletable \n");

                    /*si le fichier a déja fait plus de*/
                    if ($deletable_date > $lastModified){
                        File::delete($path);
                    }
                }
            }
        }

        return true;
    }
}

if (! function_exists('get_values')) {
    function get_values($collection,$label = "name",$value = "id"){

        return $collection->map(function ($item) use ($label,$value){
            return [
                "label" =>  $item->{$label},
                "value" =>  $item->{$value},
            ];
        })->values();
    }
}

if (! function_exists('first_date_of_period')) {
    function first_date_of_period($period = ""){
        $default_period = getSettingsOf("current_orders_period");
        $period = (blank($period)) ? $default_period  : $period;
        $period = format_date($period,"Y-m");

        $month = (blank($period)) ? date("m") : date("m",strtotime($period));
        $year = (blank($period)) ? date("Y") : date("Y",strtotime($period));
        $order = Order::where('period',$period)
                       ->whereYear('created_at',$year)
                       ->whereMonth('created_at',$month)
                      // ->latest()
                        ->get()->first();
      //  dd($period,blank($order),$order->created_at->format(__("Y-m-d")));

        return (blank($order))
            ? date("Y-m-d", strtotime("first day of $period"))
            : $order->created_at->format(__("Y-m-d")) ;
    }
}

if(!function_exists("format_date")){
    /** Format l'affichage d'une date
     * @param $date
     * @param string $format
     * @return mixed
     */
    function format_date($date,$format = "d-m-Y"){

        if ($date){
            $date = ($date instanceof DateTime) ? $date : new \Illuminate\Support\Carbon($date);
            return ($date) ? $date->format($format) : $date;
        }
        return null;

    }
}

if(!function_exists("yesNo")){
    /**Retourne la valeur booléene
     * @param int|string $value
     * @return boolean
     */
    function yesNo($value){
        return booleanVal($value) ? __("Yes") : __("No");
    }
}

if(!function_exists("booleanVal")){
    /**Retourne la valeur booléene
     * @param int|string $value
     * @return boolean
     */
    function booleanVal($value){
        return filter_var($value ?? true,FILTER_VALIDATE_BOOLEAN);
    }
}

if(!function_exists("general_error")){
    function general_error($exception = null){
        $message = __("Une erreur imprévue est survenue lors de l'opération.");
        $exceptions = [
            1
        ];
        if ( (!blank($exception) and in_array(get_class($exception),$exceptions))){
            $message = $exception->getMessage();
        }
        elseif ( (!blank($exception) and app()->environment() == "local")){
            $message = $exception->getMessage();
        }
        return $message;
    }
}

if(!function_exists("action_message")){
    function action_message($action = "",$is_success = true){
        $title = __("Opération");
        if ($action == "create"){
            $title = __("Recording");
        }
        if ($action == "update"){
            $title = __("Updating");
        }elseif ($action == "delete"){
            $title = __("Deleting");
        }
        elseif ($action == "activate"){
            $title = (booleanVal(request()->get("is_active") ?? false))
                ? __("Enabling")
                : __("Desabling");
        }
        return ($is_success) ? __("Successful :title.",['title' => $title]) : __("Failed :title",['title' => $title]);
    }
}

if (!function_exists('html_ul_lists')) {
    function html_ul_lists($datas,$class = "",$icon = " ",$style =""){
        $message = "";
        $datas = (array) $datas;
        if (!blank($datas)){
            $message = "<ul class='text-left list-unstyleds li-arrows $class' style='$style'>";
            foreach ($datas as $data){
                $message .= "<li class='text-black'> $icon $data</li>";
            }
            $message .= "</ul>";
        }
        return $message;
    }
}

if (!function_exists('activeGuard')) {
    /**retourne la guarde active
     * @return mixed
     */
    function activeGuard(){
//        if (request()->is("admin") or request()->is("admin/*")){
//            return "admin";
//        }
        $guards = array_keys(config('auth.guards'));
        if ($guards){
            foreach($guards as $guard){
                if (request()->is("admin") or request()->is("admin/*")){
                    return "admin";
                }
                if(auth()->guard($guard)->check()) return $guard;
            }
        }
        return "web";
    }
}

if(!function_exists("newId")){

    /**
     * @param string $model Le model pour lequel on veut générer un Id
     * @param int $lenght La longueur des
     * @param array $options les options supplémentaires
     * @return string
     * @throws Throwable
     */
    function newId($model = "", $lenght = 5,$options = []){
        $keyName = $options['keyName'] ?? "id";
        $prefix =  date('my');
        $separator = "";
        $error_msg = __("Le système n'a pas pu octroyer un nouvel id.");
        $raison = "";

        if (empty($model)){
            $raison = __("Le model pour lequel il faut générer un nouvel Id est manquant");
        }else{
            $instance = (new $model);

            if (!($instance instanceof Model)){
                $raison = __("$model n'est pas une instance de [Illuminate\Database\Eloquent\Model]");
            }
            elseif ($instance->getKeyName() != $keyName){
                $raison =__("Le champ $keyName n'est pas reconnu dans $model");
            }
        }

        throw_if(!empty($raison), new NewIdCannotGeneratedException($error_msg." [Raison] : $raison"));

        $period = date("Y-m-d"); // 2022-10-17
        $first_day = date("Y-m-d", strtotime("first day of $period")); // 2022-10-01
        $last_day = date("Y-m-d", strtotime("last day of $period")); // 2022-10-31
        $count_by  = ["column" => "created_at" ,'value' => [$first_day,$last_day] ];

        $count_by = (array_key_exists("count_by",$options) and (isset($options['count_by']['column']) and isset($options['count_by']['value']))  )
                    ? $options['count_by']
                    : $count_by ;

        $models = $model::withTrashed()->withoutGlobalScopes();

        if (array_key_exists("count_by",$options)){
            if (is_array($count_by['value'])){
                //$models->whereBetween($count_by['column'],$count_by['value']);
                $models->whereDate($count_by['column'],">=",$count_by['value'][0])
                       ->whereDate($count_by['column'],"<=",$count_by['value'][1]);
               //dd($models->toSql(),$count_by['value'][0],$count_by['value'][1],$options);
            }else{
                $models->where($count_by['column'],$count_by['value']);
            }
        }

        $nextId = $models->get()->count() + 1; // "1"
        $newId = format_with_char($nextId,$lenght); // "00001"
//        $date = date("my");  // "0622"
//        $newId = $date.$newId; // "CM-062200001"
        if ($options){
            if (array_key_exists("prefix",$options) and !empty($options["prefix"])){
                $prefix = $options["prefix"];
            }
            if (array_key_exists("separator",$options)){
                $separator = $options["separator"];
            }
        }
        $newId = $prefix.$separator.$newId;
        $newId = strtoupper($newId); // "CM-062200001"
        if ($model::where($keyName,$newId)->first()){
            $raison = __("'$newId' existe déjà.");
             //return newId($model,$lenght,$options);
        }

        throw_if(!empty($raison), new NewIdCannotGeneratedException($error_msg." [Raison] : $raison"));
        return $newId;
    }

if (! function_exists('get_errors_for_editor')) {

        /** <p>Formate des erreurs au fomat recue par le client "DataTable Editor"</p>
         * @param $errors
         * @return array
         */
        function get_errors_for_editor($validator){
            $result= [];
            if ($validator){
                foreach ($validator->errors()->messages() as $index => $error) {
                    $result['fieldErrors'][] = ['name' => $index, "status" =>$error[0] ?? "" ];
                }
            }
            return $result;
        }
    }
}
if (! function_exists('auth_customer')) {
    function auth_customer(){
           return auth((new Customer)->guardName())->user();
     }
}

if(!function_exists("date_is_expired")){
    /**Determine si une date est expirée par rapport à une autre
     * @param $myDate
     * @param null $compareTo
     * @param string $format
     * @return boolean
     */
    function date_is_expired($myDate,$compareTo = null, $format = "Y-m-d H:i:s"){
        $date = ($myDate instanceof DateTime) ? $myDate : date_create($myDate);
        $compareTo = $compareTo ?? date($format);
        return $date->format($format) < $compareTo;
    }
}

if (! function_exists('dt_fields_errors')) {

    /** <p>Formate des erreurs au fomat recue par le client "DataTable Editor"</p>
     * @param $errors
     * @return array
     */
    function dt_fields_errors($errors){
        $result= [];
        if ($errors){
            foreach ($errors as $index => $error) {
                $result['fieldErrors'][] = ['name' => $index, "status" =>$error[0] ?? "" ];
            }
        }
        return $result;
    }
}



