<?php

class modelGroups extends cmsModel {

    public function addGroup($group){

        $group['date_pub'] = null;

        $group_id = $this->insert('groups', $group);

        if ($group_id){
            $this->addMembership($group_id, $group['owner_id'], groups::ROLE_STAFF);
        }

        cmsCache::getInstance()->clean('groups.list');

        return $group_id;

    }

    public function updateGroupOwner($id, $owner_id){

        $membership = $this->getMembership($id, $owner_id);

        if (!$membership) {

            $this->addMembership($id, $owner_id, groups::ROLE_STAFF);

        } elseif($membership['role'] != groups::ROLE_STAFF){

            $this->updateMembershipRole($id, $owner_id, groups::ROLE_STAFF);

        }

        cmsCache::getInstance()->clean('groups.list');

        return $this->update('groups', $id, array(
            'owner_id' => $owner_id
        ));

    }

    public function updateGroup($id, $group) {

        $result = $this->update('groups', $id, $group);

        cmsCore::getModel('content')->toggleParentVisibility('group', $id, $group['is_closed']);

        cmsCache::getInstance()->clean('groups.list');

        $this->updateGroupContentParams($id, $group);

        if (empty($group['id'])) {
            $group['id'] = $id;
        }

        cmsEventsManager::hook('groups_after_update', $group);

        return $result;
    }

    public function approveGroup($id, $moderator_user_id){

        $this->update('groups', $id, array(
            'is_approved'   => 1,
            'approved_by'   => $moderator_user_id,
            'date_approved' => ''
        ));

        cmsCache::getInstance()->clean('groups.list');

        return true;

    }

    public function updateGroupContentParams($id, $group){

        $counts = $this->getGroupContentCounts($id, true);
        if (!$counts) { return true; }

        $content_model = cmsCore::getModel('content');

        foreach($counts as $ctype_name => $count){

            if (!$count['count']) { continue; }

            $content_model->filterEqual('parent_id', $id)->filterEqual('parent_type', 'group');

            $update = array('parent_title' => $group['title']);
            if(!empty($group['slug'])){
                $update['parent_url'] = href_to_rel('groups', $group['slug'], array('content', $ctype_name));
            }

            $content_model->updateFiltered($content_model->getContentTypeTableName($ctype_name), $update);

        }

        return true;

    }

    public function removeContentFromGroup($id, $is_delete=false){

        $counts = $this->getGroupContentCounts($id, true);
        if (!$counts) { return true; }

        $content_model = cmsCore::getModel('content');

        foreach($counts as $ctype_name => $count){

            if (!$count['count']) { continue; }

            $content_model->
                    filterEqual('parent_id', $id)->
                    filterEqual('parent_type', 'group');

            if ($is_delete){

                $items = $content_model->getContentItems($ctype_name);

                foreach($items as $item){
                    $content_model->deleteContentItem($ctype_name, $item['id']);
                }

            }

            if (!$is_delete){

                $content_model->updateFiltered($content_model->getContentTypeTableName($ctype_name), array(
                    'parent_id'    => null,
                    'parent_type'  => null,
                    'parent_title' => null,
                    'parent_url'   => null
                ));

            }

        }

        return true;

    }

    public function deleteGroup($group) {

        cmsEventsManager::hook('content_groups_before_delete', $group);

        $this->deleteGroupMemberships($group['id']);
        $this->deleteGroupInvites($group['id']);

        $group['ctype'] = [];
        $group['ctype_name'] = 'groups';

        foreach ($group['fields'] as $field) {
            $field['handler']->setItem($group)->delete($group[$field['name']]);
        }

        $success = $this->delete('groups', $group['id']);

        cmsCache::getInstance()->clean('groups.list');

        $this->filterEqual('child_ctype_id', null);
        $this->filterEqual('child_item_id', $group['id']);
        $this->filterEqual('target_controller', 'groups');

        $this->deleteFiltered('content_relations_bind');

        cmsEventsManager::hook('content_groups_after_delete', $group);

        return $success;
    }

    public function deleteUserGroupsAndMemberships($user_id){

        $groups = $this->filterEqual('owner_id', $user_id)->getGroups();

        if (is_array($groups)){
            foreach($groups as $group){
                $this->deleteGroup($group);
            }
        }

        $this->deleteUserMemberships($user_id);
        $this->deleteUserInvites($user_id);

    }

//============================================================================//
//============================================================================//

    public function updateGroupRating($group_id, $score){

        $this->
            filterEqual('id', $group_id)->
            increment('groups', 'rating', $score);

        cmsCache::getInstance()->clean('groups.list');

    }

//============================================================================//
//============================================================================//

    public function filterByMember($user_id){

        $this->filterEqual('m.user_id', $user_id);

        return $this->join('groups_members', 'm', 'i.id = m.group_id');

    }

//============================================================================//
//============================================================================//

    public function getGroupsCount(){

        if (!$this->approved_filter_disabled) { $this->filterApprovedOnly(); }

        return $this->getCount('groups');

    }

    public function getGroups(){

        $this->useCache('groups.list');

        if (!$this->approved_filter_disabled) { $this->filterApprovedOnly(); }

        if (!$this->order_by){ $this->orderBy('date_pub', 'desc'); }

        return $this->get('groups', function($group, $model){

            $group['slug'] = $group['slug'] ? $group['slug'] : $group['id'];

            // для связи с типами контента
            // проверка для выборки при генерации сайтмапа
            if(isset($group['owner_id'])){
                $group['ctype_name'] = 'groups';
                $group['user_id'] = $group['owner_id'];
            }

            return $group;

        });

    }

    public function getGroup($id, $field_name = 'id'){

        $this->select('u.nickname', 'owner_nickname');
        $this->select('u.slug', 'owner_slug');

        $this->join('{users}', 'u', 'u.id = i.owner_id');

        $group = $this->getItemByField('groups', $field_name, $id);

        if($group){
            $group['slug'] = $group['slug'] ? $group['slug'] : $group['id'];
            $group['content_policy'] = cmsModel::yamlToArray($group['content_policy']);
            $group['content_groups'] = cmsModel::yamlToArray($group['content_groups']);
            $group['roles']          = cmsModel::yamlToArray($group['roles']);
            $group['content_roles']  = cmsModel::yamlToArray($group['content_roles']);
            $group['join_roles']     = cmsModel::yamlToArray($group['join_roles']);
            $group['owner'] = [
                'id'       => $group['owner_id'],
                'slug'     => $group['owner_slug'],
                'nickname' => $group['owner_nickname']
            ];
            // для связи с типами контента
            $group['ctype_name'] = 'groups';
            $group['user_id'] = $group['owner_id'];
        }

        return $group;

    }

    /**
     * Псевдоним для связей
     * @param integer $id
     * @return array
     */
    public function getContentItem($id){
        return $this->getGroup($id);
    }

    public function getContentTypeTableName(...$names) {
        unset($names[0]);
        return 'groups' . implode('', $names);
    }

    public function getGroupBySlug($slug){
        return $this->getGroup($slug, 'slug');
    }

    public function getUserGroups($user_id){

        $this->useCache('groups.list');

        $this->select('g.id', 'id');
        $this->select('g.*');

        $this->joinInner('groups', 'g', 'g.id = i.group_id');

        $this->filterEqual('user_id', $user_id);

        if (!$this->order_by){
            $this->orderBy('g.title');
        }

        return $this->get('groups_members', function($group, $model){

            $group['slug'] = $group['slug'] ? $group['slug'] : $group['id'];

            return $group;

        });

    }

    public function addRole($group, $role) {

        $role_id = 1;

        $roles = array();

        if($group['roles']){

            $ids = array_keys($group['roles']);

            $role_id = max($ids) + 1;

            $roles = $group['roles'];

        }

        $roles[$role_id] = $role;

        $this->update('groups', $group['id'], array('roles' => $roles));

        cmsCache::getInstance()->clean('groups.list');

        return $role_id;

    }

    public function deleteRole($group, $role_id) {

        if(!isset($group['roles'][$role_id])){
            return false;
        }

        unset($group['roles'][$role_id]);

        $this->update('groups', $group['id'], array('roles' => $group['roles']));

        cmsCache::getInstance()->clean('groups.list');

        return true;

    }

    public function editRole($group, $role, $role_id) {

        if(!isset($group['roles'][$role_id])){
            return false;
        }

        $group['roles'][$role_id] = $role;

        $this->update('groups', $group['id'], array('roles' => $group['roles']));

        cmsCache::getInstance()->clean('groups.list');

        return true;

    }

    public function setUserRoles($group_id, $role_ids, $user_id) {

        $this->filterEqual('group_id', $group_id);
        $this->filterEqual('user_id', $user_id);
        $this->deleteFiltered('groups_member_roles');

        if(!$role_ids){ return false; }

        if(!is_array($role_ids)){
            $role_ids = array($role_ids);
        }

        foreach ($role_ids as $role_id) {
            $this->insert('groups_member_roles', array(
                'group_id' => $group_id,
                'user_id'  => $user_id,
                'role_id'  => $role_id
            ));
        }

        return true;

    }

    public function getUserRoles($group_id, $user_id) {
        return $this->filterEqual('group_id', $group_id)->
                filterEqual('user_id', $user_id)->
                get('groups_member_roles', function($item, $model){
                    return $item['role_id'];
                }, false);
    }

//============================================================================//
//============================================================================//

    public function addMembership($group_id, $user_id, $role = groups::ROLE_MEMBER){

        $id = $this->insert('groups_members', array(
            'group_id' => $group_id,
            'user_id'  => $user_id,
            'role'     => $role
        ));

        if ($id){
            $this->filterEqual('id', $group_id)->increment('groups', 'members_count');
        }

        cmsCache::getInstance()->clean('groups.members');

        return $id;

    }

    public function deleteMembership($group_id, $user_id){

        $this->filterEqual('group_id', $group_id);
        $this->filterEqual('user_id', $user_id);
        $this->deleteFiltered('groups_member_roles');

        $result = $this->
                    filterEqual('group_id', $group_id)->
                    filterEqual('user_id', $user_id)->
                    deleteFiltered('groups_members');

        if ($result){
            $this->filterEqual('id', $group_id)->decrement('groups', 'members_count');
        }

        cmsCache::getInstance()->clean('groups.members');

        return $result;

    }

    public function getMembership($group_id, $user_id){

        if (!$user_id) { return false; }

        $this->useCache('groups.members');

        return $this->
                    filterEqual('group_id', $group_id)->
                    filterEqual('user_id', $user_id)->
                    getItem('groups_members');

    }

    public function getUserMemberships($user_id){

        $this->useCache('groups.members');

        return $this->
                    filterEqual('user_id', $user_id)->
                    get('groups_members', false, 'group_id');

    }

    public function deleteGroupMemberships($group_id){

        $this->filterEqual('group_id', $group_id);
        $this->deleteFiltered('groups_member_roles');

        cmsCache::getInstance()->clean('groups.members');

        return $this->delete('groups_members', $group_id, 'group_id');

    }

    public function deleteUserMemberships($user_id){

        cmsCache::getInstance()->clean('groups.members');

        $groups_ids = array_collection_to_list($this->getUserGroups($user_id), 'id', 'id');

        if (!$groups_ids) { return false; }

        $this->filterEqual('user_id', $user_id);
        $this->deleteFiltered('groups_member_roles');

        $this->filterIn('id', $groups_ids);

        $this->decrement('groups', 'members_count');

        return $this->delete('groups_members', $user_id, 'user_id');

    }

    public function getMembersIds($group_id){

        $this->useCache('groups.members');

        return $this->
                    filterEqual('group_id', $group_id)->
                    get('groups_members', function($item, $model){

                        return $item['user_id'];

                    }, false);

    }

    public function getMembers($group_id, $role=false){

        $this->useCache('groups.members');

        $this->select('u.id', 'id');
        $this->select('u.nickname', 'nickname');
        $this->select('u.email', 'email');
        $this->select('u.avatar', 'avatar');
        $this->select('u.slug', 'slug');

        $this->join('{users}', 'u', 'u.id = i.user_id');

        if ($role !== false){
            $this->filterEqual('role', $role);
        }

        $this->filterEqual('group_id', $group_id);

        if (!$this->order_by){
            $this->orderBy ('date_updated');
        }

        return $this->get('groups_members');

    }

    public function updateMembershipRole($group_id, $user_id, $new_role){

        cmsCache::getInstance()->clean('groups.members');

        return $this->
                    filterEqual('group_id', $group_id)->
                    filterEqual('user_id', $user_id)->
                    updateFiltered('groups_members', array(
                        'role' => $new_role,
                        'date_updated' => null
                    ));

    }

//============================================================================//
//============================================================================//

    public function getInvitableGroups($user_id){

        $this->select('m.role', 'role');

        $this->joinInner('groups_members', 'm', 'm.group_id = i.id');
        $this->filterEqual('m.user_id', $user_id);

        $groups = $this->get('groups', function($group, $model){

            $is_can_invite = in_array($group['join_policy'], array(groups::JOIN_POLICY_FREE, groups::JOIN_POLICY_PUBLIC));
            $is_can_invite = $is_can_invite || (($group['join_policy'] == groups::JOIN_POLICY_PRIVATE) && ($group['role'] == groups::ROLE_STAFF));

            if (!$is_can_invite){ return false; }

            return $group;

        });

        return $groups;

    }

    public function getInvitableFriends($group_id, $for_user_id){

        $users_model = cmsCore::getModel('users');

        $friends = $users_model->orderBy('u.nickname')->getFriends($for_user_id);

        if (!$friends) { return false; }

        $group_members = $this->getMembersIds($group_id);

        foreach($friends as $id=>$friend){
            if (in_array($id, $group_members)){
                unset($friends[$id]);
            }
            if (isset($friend['privacy_options']['invite_group_users']) && !$friend['privacy_options']['invite_group_users']){
                unset($friends[$id]);
            }
        }

        return $friends;

    }

    public function addInvite($invite){

        return $this->insert('groups_invites', $invite);

    }

    public function getInvite($group_id, $invited_id){

        return $this->
                    filterEqual('group_id', $group_id)->
                    filterEqual('invited_id', $invited_id)->
                    getItem('groups_invites');

    }

    public function getInviteRequest($group_id, $user_id){

        return $this->
                    filterEqual('group_id', $group_id)->
                    filterEqual('user_id', $user_id)->
                    getItem('groups_invites');

    }

    public function deleteInvite($id){

        return $this->delete('groups_invites', $id);

    }

    public function deleteGroupInvites($group_id){

        return $this->delete('groups_invites', $group_id, 'group_id');

    }

    public function deleteUserInvites($user_id){

        $this->delete('groups_invites', $user_id, 'user_id');
        $this->delete('groups_invites', $user_id, 'invited_id');

    }

//============================================================================//
//============================================================================//

    public function filterExcludeUsersMembers($group_id, $users_model){

        $users_model->select('mr.id', 'is_send_invite');

        $users_model->joinLeft('groups_invites', 'mr', "mr.invited_id = i.id AND mr.group_id = '{$group_id}'");

        return $users_model->joinExcludingLeft('groups_members', 'm', 'm.user_id', 'i.id', "m.group_id = '{$group_id}'");

    }

    public function filterUsersMembers($group_id, $users_model){

        $users_model->select('m.role', 'member_role');
        $users_model->joinInner('groups_members', 'm', 'm.user_id = i.id');
        $users_model->filterEqual('m.group_id', $group_id);

        return $users_model;

    }

    public function filterUsersRequests($group_id, $users_model){

        $users_model->joinInner('groups_invites', 'mr', 'mr.user_id = i.id');
        $users_model->filterEqual('mr.group_id', $group_id);

        return $users_model;

    }

//============================================================================//
//============================================================================//

    public function getGroupContentCounts($id, $is_owner = false, $filter_callback = false){

        if(!is_array($id)){
            $group = array('id' => $id);
        } else {
            $group = $id;
        }

        $counts = array();

        $content_model = cmsCore::getModel('content');

        $ctypes = $content_model->getContentTypes();

        foreach($ctypes as $ctype){

            $content_model = cmsCore::getModel('content');

            if(is_callable($filter_callback)){
                $res = call_user_func_array($filter_callback, array($ctype, $content_model, $group));
                if($res === false){ continue; }
            }

            $content_model->filterEqual('parent_id', $group['id']);
            $content_model->filterEqual('parent_type', 'group');

            if ($is_owner){
                $content_model->disableApprovedFilter();
                $content_model->disablePubFilter();
                $content_model->disablePrivacyFilter();
            }

            $count = $content_model->getContentItemsCount( $ctype['name'] );

            unset($content_model);

            $counts[ $ctype['name'] ] = array(
                'count'      => $count,
                'is_in_list' => $ctype['is_in_groups'],
                'title'      => empty($ctype['labels']['profile']) ? $ctype['title'] : $ctype['labels']['profile'],
                'title_add'  => $ctype['labels']['create']
            );

        }

        return $counts;

    }

}
