<?php
    defined('BASEPATH') OR exit('No direct script access allowed');

    require_once 'notifications/NotificationGroup.php';
    require_once 'notifications/NewFollowerNotification.php';
    require_once 'notifications/PostLikeNotification.php';
    require_once 'notifications/UserRegisteredNotification.php';
    require_once 'notifications/PostMentionNotification.php';
    require_once 'notifications/PostReplyNotification.php';
    require_once 'notifications/PostReportNotification.php';
    require_once 'notifications/NotificationUser.php';
    require_once 'notifications/NewFeedbackNotification.php';

    class NotificationModel extends CI_Model
    {
        public function __construct()
        {
            parent::__construct();
            $lang = isset($_SESSION['site_lang']) ? $_SESSION['site_lang'] : 'de';
            $_SESSION['site_lang'] = $lang;
            $this->lang->load('notification', 'de');
            $this->lang->load('notification', $_SESSION['site_lang']);
        }

        public function getUserNotificationsRaw($userID, $limit = 20, $offset = 0)
        {
            $this->db->cache_off();
            $rawData = $this->db->query('SELECT n.*, count(*) count, s.username senderName, s.displayname senderDisplayname, s.profile_picture senderPicture, r.username recipientName, r.displayName recipientDisplayname FROM notifications n LEFT JOIN users s ON n.senderID = s.ID LEFT JOIN users r ON n.recipientID = r.ID WHERE recipientID = ? GROUP BY type, referenceID ORDER BY createdAt DESC, unread DESC LIMIT ? OFFSET ?', [$userID, $limit, $offset])->result_array();

            $notifications = [];
            foreach ($rawData as $notification) {
                $notificationGroup = ['count' => $notification['count']];

                if ($notificationGroup['count'] == 1) {
                    $notificationGroup['items'] = [$notification];
                } else {
                    $notificationGroup['items'] = $this->db->query('SELECT n.*, s.username senderName, s.displayname senderDisplayname, s.profile_picture senderPicture, r.username recipientName, r.displayName recipientDisplayname FROM notifications n LEFT JOIN users s ON n.senderID = s.ID LEFT JOIN users r ON n.recipientID = r.ID WHERE recipientID = ? AND type = ? AND referenceID = ? LIMIT 5', [$userID, $notification['type'], $notification['referenceID']])->result_array();
                }

                $notifications[] = $notificationGroup;
            }

            $this->db->cache_on();

            return $notifications;
        }

        public function getUserNotifications($userID, $limit = 20, $offset = 0)
        {
            $result = [];
            foreach ($notifications = $this->get($userID, $limit, $offset) as $group) {
                $date = strtotime($group->createdAt);
                $messageData = $group->message();
                $result[] = [
                    'sender' => $group->sender->getName(),
                    'unread' => $group->unread,
                    'message' => sprintf(lang($messageData['line']), ...$messageData['attributes']),
                    'link' => base_url($group->getNotificationLink()),
                    'image' => base_url($group->getNotificationImage()),
                    'time' => \Coduo\PHPHumanizer\DateTimeHumanizer::difference(new \DateTime(), new \DateTime("@$date"), $_SESSION['site_lang'])
                ];
            }

            return $result;
        }

        private function add(Notification $notification) {
            $results = $this->db->query('SELECT * FROM notifications WHERE referenceID = ? AND recipientID = ? AND senderID = ? AND type = ? AND parameters = ?', [$notification->referenceID, $notification->recipient->getID(), $notification->sender->getID(), $notification->type, $notification->parameters])->result_array();
            if(empty($results)) {
                $this->db->insert('notifications', [
                    'recipientID' => $notification->recipient->getID(),
                    'senderID' => $notification->sender->getID(),
                    'unread' => 1,
                    'type' => $notification->type,
                    'parameters' => $notification->parameters,
                    'referenceID' => $notification->referenceID,
                    'createdAt' => date('Y-m-d H:i:s', time())
                ]);
            }
            $this->db->cache_delete('Main', 'getNotifications');
        }

        public function markAsRead(array $notifications) {

        }

        public function markUserNotificationsAsRead($userID) {
            $this->db->query('UPDATE notifications SET unread = FALSE WHERE recipientID = ?', [$userID]);
        }

        public function get($userID, $limit = 20, $offset = 0) {
            $groups = [];

            $results = $this->getUserNotificationsRaw($userID, $limit, $offset);
            foreach ($results as $group) {
                $items = [];
                foreach ($group['items'] as $item) {
                    switch ($item['type']) {
                        case 'users.newFollower':
                            $items[] = new \Notification\Users\NewFollowerNotification($item);
                            break;
                        case 'users.likedPost':
                            $items[] = new \Notification\Users\PostLikeNotification($item);
                            break;
                        case 'users.mentionedPost':
                            $items[] = new \Notification\Users\PostMentionNotification($item);
                            break;
                        case 'users.repliedPost':
                            $items[] = new \Notification\Users\PostReplyNotification($item);
                            break;
                        case 'admin.newUserRegistered':
                            $items[] = new \Notification\Admin\UserRegisteredNotification($item);
                            break;
                        case 'admin.feedback':
                            $items[] = new \Notification\Admin\NewFeedbackNotification($item);
                            break;
                        case 'admin.reportedPost':
                            $items[] = new \Notification\Users\PostReportNotification($item);
                            break;
                    }
                }
                $groups[] = new NotificationGroup($items, $group['count']);
            }

            return $groups;
        }

        public function removeNotification($senderID, $recipientID, $referenceID, $type)
        {
            $this->db->query('DELETE FROM notifications WHERE senderID = ? AND recipientID = ? AND referenceID = ? AND type = ?', [$senderID, $recipientID, $referenceID, $type]);
            $this->db->cache_delete('Main', 'getNotifications');
        }

        public function userNotificationNewFollower($senderID, $recipientID) {
            $notification = new \Notification\Users\NewFollowerNotification([
                'senderID' => $senderID,
                'recipientID' => $recipientID,
                'referenceID' => $recipientID
            ]);
            $this->add($notification);
        }

        public function userNotificationPostLike($senderID, $recipientID, $postID, $postUuid) {
            $notification = new \Notification\Users\PostLikeNotification([
                'senderID' => $senderID,
                'recipientID' => $recipientID,
                'referenceID' => $postID,
                'parameters' => $postUuid
            ]);
            $this->add($notification);
        }

        public function userNotificationPostMentioned($senderID, $recipientID, $postID, $postUuid) {
            $notification = new \Notification\Users\PostMentionNotification([
                'senderID' => $senderID,
                'recipientID' => $recipientID,
                'referenceID' => $postID,
                'parameters' => $postUuid
            ]);
            $this->add($notification);
        }

        public function userNotificationPostReply($senderID, $recipientID, $postID, $postUuid) {
            $notification = new \Notification\Users\PostReplyNotification([
                'senderID' => $senderID,
                'recipientID' => $recipientID,
                'referenceID' => $postID,
                'parameters' => $postUuid
            ]);
            $this->add($notification);
        }

        public function rankNotificationNewUserRegistered($senderID, $rankRecipientID) {
            $rankUsers = $this->db->query('SELECT ID FROM users WHERE rank >= ?', [$rankRecipientID])->result_array();
            foreach ($rankUsers as $user) {
                $notification = new \Notification\Admin\UserRegisteredNotification([
                    'senderID' => $senderID,
                    'recipientID' => $user['ID'],
                    'referenceID' => $senderID,
                ]);
                $this->add($notification);
            }
        }

        public function rankNotificationNewFeedback($senderID, $rankRecipientID, $pageName) {
            $rankUsers = $this->db->query('SELECT ID FROM users WHERE rank >= ?', [$rankRecipientID])->result_array();
            foreach ($rankUsers as $user) {
                $notification = new \Notification\Admin\NewFeedbackNotification([
                    'senderID' => $senderID,
                    'recipientID' => $user['ID'],
                    'referenceID' => base_convert(md5($pageName), 16, 10) % 9999
                ]);
                $this->add($notification);
            }
        }

        public function rankNotificationPostReport($senderID, $rankRecipientID, $postID, $postUUID) {
            $rankUsers = $this->db->query('SELECT ID FROM users WHERE rank >= ?', [$rankRecipientID])->result_array();
            foreach ($rankUsers as $user) {
                $notification = new \Notification\Users\PostReportNotification([
                    'senderID' => $senderID,
                    'recipientID' => $user['ID'],
                    'referenceID' => $postID,
                    'parameters' => $postUUID
                ]);
                $this->add($notification);
            }
        }

    }