<?php

namespace App\Http\Controllers\Systems;

use Illuminate\Support\Str;
use Illuminate\Http\Request;
use App\Events\Notifications;
use App\Http\Classes\Notification;
use App\Http\Controllers\Controller;
use App\Models\Notifications\NotificationMessages;
use App\Models\User;
use Carbon\Carbon;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Redis;
use Suiterus\Dms\Models\Approvals\Approval;
use Suiterus\Dms\Models\Approvals\UserApprover;
use Suiterus\Dms\Models\Files\File;
use Suiterus\Dms\Models\Files\Forward;
use Suiterus\Dms\Models\Signatory\FileSignatorySignee;

class NotificationController extends Controller
{
    /*
        status:1 = unread
        status:2 = read
    */

    public function createNotification(Request $request)
    {
        $this->sendNotification($request->all());
    }

    public static function sendNotification($notification)
    {
        $request = json_decode(json_encode($notification));
        $request->id = Str::uuid()->toString();
        // Carbon::today()->addDays(rand(1, 365)) //random date
        $request->created_at = Carbon::now();
        $request->status = 1;

        $receiver_id = $request->receiver_id;
        $userNotification = json_encode($request);

        $redis = Redis::connection();

        $redis->zadd('user:' . $receiver_id . ':notification:unread', time(), $userNotification);
        $redis->zadd('user:' . $receiver_id . ':notification:all', time(), $userNotification);

        $notification = json_decode($userNotification);
        $notificationMessages = NotificationMessages::where('id', $notification->notification_id)->first();
        $notification->title = $notificationMessages->header;
        $notification->message = $notification->send_to == 'sender' ? $notificationMessages->sender_message : $notificationMessages->receiver_message;
        $notification->sender = User::where('id', $notification->sender_id)->first();
        $notification->receiver = User::where('id', $notification->receiver_id)->first();

        if (isset($notification->user_approver_id)) {
            $userApprover = json_decode(json_encode(UserApprover::where('id', $notification->user_approver_id)->with(['fileApprover', 'fileApprover.approval', 'fileApprover.approval.file'])->first()), true);
            $notification->file_name = $userApprover['file_approver']['approval']['file']['file_name'];
        } else if (isset($notification->forward_id)) {
            $forward = json_decode(json_encode(Forward::where('id', $notification->forward_id)->with('file')->first()), true);
            $notification->file_name = $forward['file']['name'];
            $notification->file_id = $forward['file']['id'];
        } else if (isset($notification->file_signatory_signee_id)) {
            $fileSignatorySignee = json_decode(json_encode(FileSignatorySignee::where('id', $notification->file_signatory_signee_id)->with(['fileSignatory.fileVersion'])->first()), true);
            $notification->file_name = $fileSignatorySignee['file_signatory']['file_version']['file_name'];
        }

        broadcast(new Notifications($notification, $receiver_id))->toOthers();
    }

    public function getAllNotifications(Request $request)
    {
        $redis = Redis::connection();
        $notificationObj = new Notification($redis);

        $notifications = [];
        if ($request->filter_type == 'today') {
            $notifications = $notificationObj->today($request, 'all');
        } else if ($request->filter_type == 'yesterday') {
            $notifications = $notificationObj->yesterday($request, 'all');
        } else if ($request->filter_type == 'this_week') {
            $notifications = $notificationObj->thisWeek($request, 'all');
        } else if ($request->filter_type == 'this_month') {
            $notifications = $notificationObj->thisMonth($request, 'all');
        } else if ($request->filter_type == 'this_year') {
            $notifications = $notificationObj->thisYear($request, 'all');
        }


        return $this->addObjectToNotifications($notifications);
    }

    public function getNewNotification(Request $request)
    {
        $redis = Redis::connection();

        $ts = time() - (86400 * 1);

        $notifications = $redis->zrevrangebyscore('user:' . Auth::id() . ':notification:unread', '+inf', $ts, 'limit', $request->off_set, $request->count, 'withscores');


        $convertedNotifications = $this->addObjectToNotifications($notifications);

        $notifications = $redis->zrevrangebyscore('user:' . Auth::id() . ':notification:read', '+inf', $ts, 'limit', $request->off_set, $request->count, 'withscores');

        array_push($convertedNotifications, ...$this->addObjectToNotifications($notifications));

        return $convertedNotifications;
    }

    public function getOldNotification(Request $request)
    {
        $redis = Redis::connection();

        $ts = time() - (86400 * 1);

        $notifications = $redis->zrevrangebyscore('user:' . Auth::id() . ':notification:unread', $ts, '-inf', 'limit', $request->off_set, $request->count, 'withscores');


        $convertedNotifications = $this->addObjectToNotifications($notifications);

        $notifications = $redis->zrevrangebyscore('user:' . Auth::id() . ':notification:read', $ts, '-inf', 'limit', $request->off_set, $request->count, 'withscores');

        array_push($convertedNotifications, ...$this->addObjectToNotifications($notifications));

        return $convertedNotifications;
    }

    public function getReadNotification(Request $request)
    {
        $redis = Redis::connection();
        $notificationObj = new Notification($redis);
        $notifications = [];

        if (isset($request->filter_type)) {
            if ($request->filter_type == 'today') {
                $notifications = $notificationObj->today($request, 'read');
            } else if ($request->filter_type == 'yesterday') {
                $notifications = $notificationObj->yesterday($request, 'read');
            } else if ($request->filter_type == 'this_week') {
                $notifications = $notificationObj->thisWeek($request, 'read');
            } else if ($request->filter_type == 'this_month') {
                $notifications = $notificationObj->thisMonth($request, 'read');
            } else if ($request->filter_type == 'this_year') {
                $notifications = $notificationObj->thisYear($request, 'read');
            }
        } else {
            $notifications = $notificationObj->getNotificationByType($request, 'read');
        }


        return $this->addObjectToNotifications($notifications);
    }

    public function getUnreadNotification(Request $request)
    {
        $redis = Redis::connection();
        $notificationObj = new Notification($redis);

        if (isset($request->filter_type)) {
            if ($request->filter_type == 'today') {
                $notifications = $notificationObj->today($request, 'unread');
            } else if ($request->filter_type == 'yesterday') {
                $notifications = $notificationObj->yesterday($request, 'unread');
            } else if ($request->filter_type == 'this_week') {
                $notifications = $notificationObj->thisWeek($request, 'unread');
            } else if ($request->filter_type == 'this_month') {
                $notifications = $notificationObj->thisMonth($request, 'unread');
            } else if ($request->filter_type == 'this_year') {
                $notifications = $notificationObj->thisYear($request, 'unread');
            }
        } else {
            $notifications = $notificationObj->getNotificationByType($request, 'unread');
        }


        return $this->addObjectToNotifications($notifications);
    }

    public function getCountAllUnreadNotification(Request $request)
    {
        $redis = Redis::connection();
        $notificationObj = new Notification($redis);

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

            if ($request->filter_type == 'today') {
                $notifications = $notificationObj->countToday('unread');
            } else if ($request->filter_type == 'yesterday') {
                $notifications = $notificationObj->countYesterday('unread');
            } else if ($request->filter_type == 'this_week') {
                $notifications = $notificationObj->countThisWeek('unread');
            } else if ($request->filter_type == 'this_month') {
                $notifications = $notificationObj->countThisMonth('unread');
            } else if ($request->filter_type == 'this_year') {
                $notifications = $notificationObj->countThisYear('unread');
            }
        } else {
            $notifications = $notificationObj->countNotificationByType('unread');
        }

        return $notifications;
    }

    public function markNotificationAsRead(Request $request)
    {
        $redis = Redis::connection();
        $requestNotification = $request->all();

        $this->markAsRead($redis, $requestNotification, $request->score);

        $notifications = $redis->zrevrangebyscore('user:' . Auth::id() . ':notification:unread', '+inf', '-inf');

        $convertedNotifications = [];

        foreach ($notifications as $notification) {
            array_push($convertedNotifications, json_decode($notification));
        }

        return $convertedNotifications;
    }

    public function markAsRead($redis, $requestNotification, $score)
    {
        $requestNotification = $this->unsetExcessNotificationObject($requestNotification);

        $redis->zrem('user:' . Auth::id() . ':notification:unread', json_encode($requestNotification));
        $redis->zrem('user:' . Auth::id() . ':notification:all', json_encode($requestNotification));

        $requestNotification = json_decode(json_encode($requestNotification));
        $requestNotification->status = 2;
        $redis->zadd('user:' . Auth::id() . ':notification:read', $score, json_encode($requestNotification));
        $redis->zadd('user:' . Auth::id() . ':notification:all', $score, json_encode($requestNotification));
    }

    public function markNotificationAsUnread(Request $request)
    {
        $redis = Redis::connection();
        $requestNotification = $request->all();
        $requestNotification = $this->unsetExcessNotificationObject($requestNotification);

        $redis->zrem('user:' . Auth::id() . ':notification:read', json_encode($requestNotification));
        $redis->zrem('user:' . Auth::id() . ':notification:all', json_encode($requestNotification));

        $requestNotification = json_decode(json_encode($requestNotification));
        $requestNotification->status = 1;
        $redis->zadd('user:' . Auth::id() . ':notification:unread', $request->score, json_encode($requestNotification));
        $redis->zadd('user:' . Auth::id() . ':notification:all', $request->score, json_encode($requestNotification));


        $notifications = $redis->zrevrangebyscore('user:' . Auth::id() . ':notification:read', '+inf', '-inf');

        $convertedNotifications = [];

        foreach ($notifications as $notification) {
            array_push($convertedNotifications, json_decode($notification));
        }

        return $convertedNotifications;
    }

    public function deleteNotification(Request $request)
    {
        $redis = Redis::connection();
        $requestNotification = $request->all();
        $requestNotification = $this->unsetExcessNotificationObject($requestNotification);

        if ($request->status == 1) {
            $redis->zrem('user:' . Auth::id() . ':notification:unread', json_encode($requestNotification));
            $redis->zadd('user:' . Auth::id() . ':notification:deleted', $request->score, json_encode($requestNotification));
        } else {
            $redis->zrem('user:' . Auth::id() . ':notification:read', json_encode($requestNotification));
            $redis->zadd('user:' . Auth::id() . ':notification:deleted', $request->score, json_encode($requestNotification));
        }

        $redis->zrem('user:' . Auth::id() . ':notification:all', json_encode($requestNotification));

        return response()->json($requestNotification);
    }

    // Everytime you add an object to notification, you need to use the unset function.
    public function addObjectToNotifications($notifications)
    {
        $convertedNotifications = [];
        foreach ($notifications as $notification => $score) {
            $notification = json_decode($notification);
            $notificationMessages = NotificationMessages::where('id', $notification->notification_id)->first();
            $notification->title = $notificationMessages->header;
            $notification->message = $notification->send_to == 'sender' ? $notificationMessages->sender_message : $notificationMessages->receiver_message;
            $notification->score = $score;
            $notification->sender = User::where('id', $notification->sender_id)->first();
            $notification->receiver = User::where('id', $notification->receiver_id)->first();

            if (isset($notification->user_approver_id)) {
                $userApprover = UserApprover::where('id', $notification->user_approver_id)->with(['fileApprover', 'fileApprover.approval', 'fileApprover.approval.file'])->first();
                if ($userApprover) {
                    $userApproverAsArray = json_decode(json_encode($userApprover), true);
                    $notification->file_name = $userApproverAsArray['file_approver']['approval']['file']['file_name'] ?? '';
                }
            } else if (isset($notification->forward_id)) {
                $forward = Forward::where('id', $notification->forward_id)->with('file')->first();
                if ($forward) {
                    $forwardAsArray = json_decode(json_encode($forward), true);
                    $notification->file_name = $forwardAsArray['file']['name'];
                    $notification->file_id = $forwardAsArray['file']['id'];
                }
            } else if (isset($notification->file_signatory_signee_id)) {
                $fileSignatorySignee = FileSignatorySignee::where('id', $notification->file_signatory_signee_id)->with(['fileSignatory.fileVersion'])->first();
                if ($fileSignatorySignee) {
                    $fileSignatorySigneeAsArray = json_decode(json_encode($fileSignatorySignee), true);
                    $notification->file_name = $fileSignatorySigneeAsArray['file_signatory']['file_version']['file_name'];
                }
            }
            array_push($convertedNotifications, $notification);
        }
        return $convertedNotifications;
    }

    public function unsetExcessNotificationObject($requestNotification)
    {
        unset($requestNotification['score']);
        unset($requestNotification['progress_bar_value']);
        unset($requestNotification['buffer_value']);
        unset($requestNotification['delete_interval']);
        unset($requestNotification['is_notification_deleted']);
        unset($requestNotification['delete_timeout']);
        unset($requestNotification['undo_delete_timeout']);
        unset($requestNotification['is_undo_delete_clicked']);
        unset($requestNotification['sender']);
        unset($requestNotification['receiver']);
        unset($requestNotification['title']);
        unset($requestNotification['message']);
        unset($requestNotification['file_name']);
        return $requestNotification;
    }

    public function markAllTodayNotificationAsRead()
    {
        $redis = Redis::connection();
        $notificationObj = new Notification($redis);

        $notifications = [];

        $notifications = $notificationObj->today(null, 'all');

        $notifications = $this->addObjectToNotifications($notifications);

        foreach ($notifications as $notification) {
            $notification = json_decode(json_encode($notification), true);
            $this->markAsRead($redis, $notification, $notification['score']);
        }

        return $notifications;
    }
}
