<?php

namespace App\Http\Controllers\API\v1;

use App\Http\Controllers\BaseController;
use App\Http\Requests\MediaStoreRequest;
use App\Jobs\SendNotificationToFirebase;
use Illuminate\Support\Facades\Log;

use App\Jobs\SendEmailJob;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Exception;

use Carbon\Carbon;

class NotificationController extends BaseController
{

    public function test(Request $request) {
        
        $request->{"type"} = "RATE";
        $request->{"ecu_id"} = "3053";
        $request->{"user_id"} = "20";
        $request->{"media_id"} = "146";
        $request->{"nUrl"} = "http://127.0.0.1:8005/notifications/:p1/update";
        $request->{"callback"} = [
            'prof' => "http://127.0.0.1:8005/professeur/courses/:p1/view",
            'student' => "http://127.0.0.1:8005/students/courses/:p1/lessons",
            'authUrl' => "http://127.0.0.1:8005/auth",
        ];


        /*
            // In store_notification

            $last_id = 93;
            $result = [
                "users_ids" => [
                    "prof" => [
                    19
                    ],
                    "students" => [
                        0 => 52,
                        1 => 53,
                        2 => 54,
                    ],
                ],
                "users_emails" => [
                    "prof" => [
                        19 => "agbvfr@gmail.com",
                    ],
                    "students" => [
                        52 => "henograce1@gmail.com",
                        53 => "jimhessanon2000@gmail.com",
                        54 => "agbvfr@gmail.com",
                    ],
                ],
            ];
        */
        
        // $rep = $this->store_notification($request);

        $rep = $this->store_user_notifications("RATE",3,3053,20);

        return sendResponse([$rep], "TEST");
    }

    //Sauvegarder une notification

    public function store_notification(Request $request) {

        try {

            $last_id = DB::connection('tenant')
            ->table('notifications')
            ->insertGetId([
                'type' => $request->type,
                'ecu_id' => $request->ecu_id,
                'id_media' => isset($request->media_id) ? $request->media_id : null
            ]);

            $last_notif = DB::connection('tenant')
                    ->table('notifications')
                    ->where('id', $last_id)
                    ->first();


            //On attribue la notification aux users concernes . Le retour de la fonction est l'ensemble de leurs ids.

            $result = $this->store_user_notifications($request->type,$last_id,$request->ecu_id,$request->user_id);

            if ($result == false) {
                return sendError('SOME_ERROR_FOR_THIS_OPERATION');
            }

            //Envoie des donnees de notifications au front-end

                //Prendre les tokens des users

                if ($result['users_ids']['prof'] != []){
                    $token_prof = $this->get_token($result['users_ids']['prof']);
                }

                if($result['users_ids']['students'] != []){
                    $tokens = $this->get_token($result['users_ids']['students']);
                }

                //Prendre les infos au sujet de la notification
                $intituleMedia = ''; // precaution...

                if (isset($request->media_id)) {

                    $data = $this->notifs_block($request->media_id,$request->ecu_id);
                    //Log::alert("message : " . array_key_first($data['medias']->titre));

                    //$intituleMedia = array_key_first($data['medias']->titre);
                    $intituleMedia = $data['medias'][array_key_first($data['medias'])][0]->titre;

                } else {

                    $data = $this->notifs_block(null,$request->ecu_id);

                }

                //$result = ['tokens' => $tokens, 'notif_data' => $notif_data];

                $intituleEcu = $data['ecus'][array_key_first($data['ecus'])][0]['intituleEcu'];

                $messages = [
                    "DEVOIR" => "Nouveau devoir programmé pour cet EC",
                    "COURS" => "Nouveau cours programmé pour cet EC",
                    "MEDIA"  => "Nouveau média disponible. Média intitulé <b> " . $intituleMedia . "</b>" ,
                    "COMMENTAIRE" => "Nouveau commentaire sur le media intitulé <b> " . $intituleMedia . "</b>",
                    "RATE"  => "Un étudiant vient d'évaluer le média intitulé <b> " . $intituleMedia . "</b>"
                ];

                if ($result['users_ids']['prof'] != []){
                    $notif_data = [
                        'title' => "$intituleEcu",
                        'body' => $messages[$request->type],
                        'nUrl' => str_replace(":p1",secure_me($last_id),$request->nUrl),
                        'callback' => str_replace(":p1",secure_me($request->ecu_id),$request->callback['prof']),
                        'type' => "$request->type",
                        'id_media' => isset($request->media_id) ? secure_me($request->media_id) : "",
                        'created_at' => "$last_notif->created_at",
                    ];

                    $this->send_notification($token_prof,$notif_data);
                    // $this->send_email( // TODO : Uncomment email
                    //     $result['users_ids']['prof'],
                    //     $result['users_emails']['prof'],
                    //     $last_id,
                    //     $notif_data
                    // );
                }

                if($result['users_ids']['students'] != []){
                    $notif_data = [
                        'title' => "$intituleEcu",
                        'body' => $messages[$request->type],
                        'nUrl' => str_replace(":p1",secure_me($last_id),$request->nUrl),
                        'callback' => str_replace(":p1",secure_me($request->ecu_id),$request->callback['student']),
                        'type' => "$request->type",
                        'id_media' => isset($request->media_id) ? secure_me($request->media_id) : "",
                        'created_at' => "$last_notif->created_at"
                    ];

                    if(isset($request->published_at)){
                        // $request->published_at has a format like this : 2020-11-17 00:00:00 (type string)

                        $actualDate = Carbon::now()->toDateTimeString();
                        $futureDate = $request->published_at;

                        $diff = strtotime($futureDate) - strtotime($actualDate);

                        $this->send_notification($tokens,$notif_data,$diff);
                        // $this->send_email( // TODO : Uncomment email
                        //     $result['users_ids']['students'],
                        //     $result['users_emails']['students'], 
                        //     $last_id, 
                        //     $notif_data, 
                        //     $diff
                        // );
                    }
                    else{
                        $this->send_notification($tokens,$notif_data);
                        // $this->send_email( // TODO : Uncomment email
                        //     $result['users_ids']['students'],
                        //     $result['users_emails']['students'],
                        //     $last_id,
                        //     $notif_data
                        // );
                    }
                }

            return true;

            /*$countMinutesJob = (new CountMinutes())->delay(Carbon::now()->addMinutes(1));

            dispatch($countMinutesJob);

            return sendResponse([],'DATA_GOT_SUCCESSFULLY');*/

        } catch (Exception $e) {
            return $e->getMessage();
        }
    }

    //Lier des notifications aux utilisateurs

    private function store_user_notifications($notif_type,$id_notif,$ecu_id,$user_id) {

        try {

            $users_ids = ["prof" => [], "students" => []];
            $users_emails = ["prof" => [], "students" => []];

            // On s'occupe d'abord de tous les types de notification sauf les RATE

            if ($notif_type != 'RATE') {
                // Cas d'un devoir, d'un cours, d'un media ou d'un simple commentaire
                
                // Recuperer les etudiants ayant l'ecu
                $server_response = $this->students_ecu($ecu_id);
                if($server_response && $server_response['success']){

                    $ecus_data = $server_response['data'];

                    $user = DB::connection('tenant')
                        ->table('users')
                        ->where('id',$user_id)
                        ->get()->first();

                    $array_data = [];

                    // On attribue la notification a tous les étudiants (sauf celui qui a fait l'action s'il est un étudiant)
                    $ec_students = array_merge(
                        $ecus_data['students_normal'], 
                        $ecus_data['students_reprise']
                    );

                    foreach ($ec_students as $data) {
                        if ($data['matricule'] != $user->matricule) {

                            $u = DB::connection('tenant')
                            ->table('users')
                            ->where('matricule',$data['matricule'])
                            ->get()
                            ->first()
                            ;

                            if ($u) {
                                $id = $u->id;
                            } else { 
                                // user hasn't connected yet on our platform
                                // Let's create an entry for him in order to link notifs to him
                                $id = DB::connection('tenant')->table('users')
                                ->insertGetId([
                                    'matricule' => $data['matricule'],
                                    'access_token' => 'AUTOMATIC',
                                    "refresh_token" => 'AUTOMATIC',
                                    'type_user' => 0,
                                    'expire_at' => Carbon::now()->toDateTimeString(),
                                ]);
                            }
                            
                            array_push($array_data,['user_id' => $id , 'notification_id' => $id_notif]);
                            array_push($users_ids["students"],$id);
                            $users_emails["students"]["$id"] = $data['email'];
                        }
                    }

                    if ($notif_type == 'COMMENTAIRE' && $user->type_user == 0) {
                        //On attribue la notification a son professeur

                        $id = DB::connection('tenant')
                            ->table('users')
                            ->where('matricule',$ecus_data['prof'][0]['matricule'])
                            ->get()->first()->id;

                        array_push($array_data,['user_id' => $id , 'notification_id' => $id_notif]);
                        array_push($users_ids["prof"],$id);
                        $users_emails["prof"]["$id"] = $data['email'];
                    }

                    // insert data in DB
                    DB::connection('tenant')
                    ->table('user_notifications')
                    ->insert($array_data)
                    ;

                    return ['users_ids' => $users_ids, 'users_emails' => $users_emails];
                } else {

                    return false;

                }

            } else {

                // Recuperer le prof en charge de l'ECU

                $server_response = $this->get_prof_ecu($ecu_id);
                if($server_response && $server_response['success']) {

                    $prof_matricule = $server_response['data']['prof'][0]['matricule'];
                    $prof_email = $server_response['data']['prof'][0]['email'];

                    $id = DB::connection('tenant')
                        ->table('users')
                        ->where('matricule',$prof_matricule)
                        ->get()->first()->id;

                    array_push($users_ids["prof"],$id);
                    $users_emails["prof"]["$id"] = $prof_email;

                    DB::connection('tenant')
                        ->table('user_notifications')
                        ->insert([
                            'user_id' => $id,
                            'notification_id' => $id_notif
                        ]);

                    //return $users_ids;
                    return ['users_ids' => $users_ids, 'users_emails' => $users_emails];

                } else {

                    return false;

                }

            }

        } catch (Exception $e) {
            // return $e->getMessage();
            return false;
        }
    }

    // Etudiants ayant une ECU donnee

    public function students_ecu($ecuId){

        $server_response = reqGest('GET','v1/ecus/'. secure_me($ecuId,true).'/students_ecu',[],2);

        return $server_response;

    }

    // Recuperer le prof en charge d'une ECU

    public function get_prof_ecu ($ecu_id) {

        $server_response = reqGest('POST','v1/ecus/prof', ['ecuIds' => [$ecu_id]],2);

        return $server_response;
    }

    //Mettre a jour une notification. Elle est marquee comme lue.

    public function update(Request $request,$notification_id) {

        try {

            $userId = $request->get('User')->id;

            $result = DB::connection('tenant')
                ->table('user_notifications')
                ->where('user_id',$userId)
                ->where('notification_id',$notification_id)
                ->update([
                    'statut' => 'READ'
                ]);

            return sendResponse([],'DATA_UPDATED_SUCCESSFULLY');

        } catch (Exception $e) {
            return sendError("SERVER ERROR, PLEASE CONTACT ADMINISTRATOR", $e->getMessage(), 400);
        }
    }

    //Recuperer le nombre de notifications non lues par un utilisateur

    private function get_unread_notifs($userId) {
        try {

            $total = DB::connection('tenant')
                ->table('user_notifications')
                ->where('user_id',$userId)
                ->where('statut','UNREAD')
                ->get()->count();

            return $total;

        } catch (Exception $e) {
            return false;
        }
    }

    //Prendre les dernieres notifications en rapport a un utilisateur

    private function get_last_notifs ($userId,$limit) {
        try {

            $notifs = DB::connection('tenant')
                ->table('user_notifications')
                ->where('user_id',$userId)
                ->orderByDesc('created_at')
                ->take($limit)
                ->join('notifications','user_notifications.notification_id','=','notifications.id')
                ->get();

            return $notifs;

        } catch (Exception $e) {
            return false;
        }
    }

    //Prendre les infos d'un media

    private function get_infos_medias ($medias_ids) {
        try {

            $medias = DB::connection('tenant')
                ->table('medias')
                ->whereIn('id',$medias_ids)
                ->get()
                ->groupBy('id');

            $medias = encryptKeys($medias);

            return $medias;

        } catch (Exception $e) {
            return false;
        }
    }

    //Prendre les infos d'un ecu

    private function get_infos_ecus ($ecus_ids) {

        $toSend = [];

        foreach ($ecus_ids as $key => $value) {
            // $toSend["id_$key"] = $value;
            $toSend["id_$key"] = secure_me($value,true); // crypt ids b4 sending to ohter api
        }

        // $server_response = getFromGest('api/v1/ecus/infos',['codes_ecus' => $codes_ecus,'bd' => substr($CurrentDb, 10)])->json();
        $server_response = reqGest('POST','v1/ecus/infos',['ecuIds' => $toSend],2);

        return $server_response;

    }

    // Toutes les donnees d'affichage de notifications chez un utlisateur

    private function notifs_block ($id_media = null,$ecu_id) {
        try {

            /*$result = $this->get_unread_notifs($user_id);

            if ($result == false) {
                return sendError('SOME_ERROR_OCCURED');
            }

            $unread = $result;

           // $result = $this->get_last_notifs($user_id,3);
           $result = $this->get_last_notifs($user_id,1);

            if ($result == false) {
                return sendError('SOME_ERROR_OCCURED');
            }

            $latest = $result;*/

            /*$medias_ids = $latest->pluck('idMedia');
            $medias_ids = array_unique($medias_ids->toArray());

            $codes_ecus = $latest->pluck('code_ecu');
            $codes_ecus = array_unique($codes_ecus->toArray());*/

            //$result = $this->get_infos_medias($medias_ids);
            if ($id_media) {

                $result = $this->get_infos_medias([$id_media]);

                if ($result == false) {
                    //return sendError('SOME_ERROR_OCCURED');
                    return false;
                }

                $medias = $result;

            } else {
                $medias = [];
            }

            //$result = $this->get_infos_ecus($codes_ecus,$request->get('CurrentDb'));
            $result = $this->get_infos_ecus([$ecu_id]);

            if (isset($result['success']) && $result['success'] == true) {
                $ecus = $result['data'];
            } else {
                //return sendError('SOME_ERROR_OCCURED');
                return false;
            }


            /*$notifs = [
                'unread' => $unread,
                'latest' => $latest,
                'data' => [
                    'medias' => $medias,
                    'ecus' => $ecus
                ]
            ];*/

            $data = [
                'medias' => $medias,
                'ecus' => $ecus
            ];

            //return sendResponse($notifs,'DATA_GOT_SUCCESSFULLY');
            return $data;

        } catch (Exception $e) {
            return false;
        }
    }

    // Toutes les notifications d'un utilisateur

    public function all_notifs (Request $request) {

        try {

            $userId = $request->get('User')->id;

            $result = $this->get_unread_notifs($userId);

            if ($result === false) {
                return sendError('SOME_ERROR_OCCURED');
            }

            $unread = $result;

            $notifs = DB::connection('tenant')
                ->table('user_notifications')
                ->where('user_id',$userId)
                ->skip($request->offset)
                ->take($request->perPage)
                ->join('notifications','user_notifications.notification_id','=','notifications.id')
                ->orderByDesc('created_at')
                ->get();

            $medias_ids = $notifs->pluck('id_media');
            $ecus_ids = $notifs->pluck('ecu_id');

            $medias_ids = array_unique($medias_ids->toArray());
            $ecus_ids = array_unique($ecus_ids->toArray());

            $result = $this->get_infos_medias($medias_ids);

            if ($result === false) {
                return sendError('SOME_ERROR_OCCURED');
            }

            $medias = $result;
            $result = $this->get_infos_ecus($ecus_ids);

            if (isset($result['success']) && $result['success'] == true) {
                $ecus = $result['data'];
            } else {
                return sendError('SOME_ERROR_OCCURED');
            }

            // $ecus = $result['data'];

            //Nombre total de notification de l'utilisateur

            $total_notifs = DB::connection('tenant')
                ->table('user_notifications')
                ->where('user_id',$userId)
                ->get()->count();

            $data = [
                'unread' => $unread,
                'total' => $total_notifs,
                'latest' => $notifs,
                'data' => [
                    'medias' => $medias,
                    'ecus' => $ecus
                ]
            ];

            return sendResponse($data,'DATA_GOT_SUCCESSFULLY');

        } catch (Exception $e) {
            return sendError("SERVER ERROR, PLEASE CONTACT ADMINISTRATOR", $e->getMessage(), 400);
        }

    }

    private function get_token ($users_ids) {
        try {

            $tokens = DB::connection('tenant')
                ->table('users')
                ->whereIn('id',$users_ids)
                ->where('user_authorization','YES')
                ->get()->pluck('device_token');

            return $tokens;

        } catch (Exception $e) {
            return $e->getMessage();
        }
    }

    public function send_email ($ids, $emails, $notification_id, $notif_data, $delay = 0) {

        if($delay != 0){
            // $delay += 180;
            $delay += 8;
            $emailJob = (new SendEmailJob($ids, $emails, $notification_id, $notif_data))->delay(Carbon::now()->addSeconds($delay));
        }else{
            // $delay = 180;
            $delay = 8;
            $emailJob = (new SendEmailJob($ids, $emails, $notification_id, $notif_data))->delay(Carbon::now()->addSeconds($delay));
        }

        $this->dispatch($emailJob);
    }

    public function send_notification ($tokens,$notif_data, $delay = 0) {

        if($delay != 0){
            $notifJob = (new SendNotificationToFirebase($tokens,$notif_data))->delay(Carbon::now()->addSeconds($delay));
        }
        else{
            $delay = 5;
            $notifJob = (new SendNotificationToFirebase($tokens,$notif_data))->delay(Carbon::now()->addSeconds($delay));
        }

        $this->dispatch($notifJob);
    }

    public function update_choice (Request $request) {

        try {

            $userId = $request->get('User')->id;

            $result = DB::connection('tenant')
                ->table('users')
                ->where('id',$userId)
                ->update([
                    'device_token' => $request->token,
                    'user_authorization' => $request->choice
                ]);

            return sendResponse([],'CHOICE_UPDATED_SUCCESSFULLY');

        } catch (Exception $e) {
            return sendError("SERVER ERROR, PLEASE CONTACT ADMINISTRATOR", $e->getMessage(), 400);
        }
    }

}
