<?php

namespace Ignite\Core\Entities;

use Ignite\Core\Collections\GroupsCollection;

/**
 * Group Entity.
 *
 * @property \Illuminate\Database\Eloquent\Collection groups
 */
class Group extends Base
{
    const ACTIVE = 1;
    const INACTIVE = 0;

    const LEVEL_SUPER_ADMIN = 1;
    const LEVEL_MANAGER = 2;
    const LEVEL_SPECIALIST = 4;
    const LEVEL_CLIENT = 8;
    const LEVEL_PARTICIPANT = 16;

    /**
     * The custom table name.
     * @var string
     */
    protected $table = 'core_group';

    /**
     * @var array
     */
    protected $casts = [
        'is_user_defined' => 'bool'
    ];

    /**
     * Eloquent event listeners.
     */
    public static function boot()
    {
        parent::boot();
        static::saving(function (Group $model) {
            if (empty(trim($model->key))) {
                $model->key = str_slug($model->name);
            }
            if (empty(trim($model->status))) {
                $model->status = static::INACTIVE;
            }
        });
        static::saved(function () {
            app('authorization')->forgetPermissions()->registerPermissions();
        });
        static::deleting(function (Group $model) {
            if (! $model->isUserDefined()) {
                throw new \Exception('You cannot delete a system defined user group.');
            }
        });
    }

    /**
     * The users related to this group.
     *
     * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
     */
    public function users()
    {
        return $this->belongsToMany(User::class, 'core_user_group', 'group_id', 'user_id')->withTimestamps();
    }

    /**
     * The relationship to the permissions for this group.
     *
     * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
     */
    public function permissions()
    {
        return $this->belongsToMany(Permission::class, 'core_group_permission', 'group_id', 'permission_id')->withTimestamps();
    }

    /**
     * Assign a permission to the role.
     *
     * @param  Permission $permission
     * @return Model
     */
    public function givePermissionTo(Permission $permission)
    {
        $this->permissions()->save($permission);

        return $this;
    }

    /**
     * Determine if the group has the provided permission.
     *
     * @param  string|Permission $permission
     * @return bool
     */
    public function hasPermission($permission)
    {
        if (is_string($permission)) {
            return $this->permissions->contains('key', $permission);
        }

        if ($permission instanceof Permission) {
            return $this->permissions->contains($permission);
        }

        return false;
    }

    /**
     * Determine if the group has users.
     *
     * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany|Group
     * @deprecated
     */
    public function hasUsers()
    {
        return $this->users()->select('group_id');
    }

    /**
     * Determine if the group has permissions.
     *
     * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
     * @deprecated
     */
    public function hasPermissions()
    {
        return $this->permissions()->select('group_id');
    }

    /**
     * Determine if the group is user-defined.
     *
     * @return bool
     */
    public function isUserDefined()
    {
        return (bool) $this->is_user_defined;
    }

    /**
     * Determine if the group is active.
     *
     * @return bool
     */
    public function isActive()
    {
        return $this->status === static::ACTIVE;
    }

    /**
     * Determine if the group is inactive.
     *
     * @return bool
     */
    public function isInactive()
    {
        return $this->status === static::INACTIVE;
    }

    /**
     * The default system levels.
     *
     * @return array
     */
    public function getSystemLevels()
    {
        return [
            self::LEVEL_SUPER_ADMIN,
            self::LEVEL_MANAGER,
            self::LEVEL_SPECIALIST,
            self::LEVEL_CLIENT,
            self::LEVEL_PARTICIPANT,
        ];
    }

    /**
     * Determine if the instance level is a system level.
     *
     * @return bool
     */
    public function isSystemLevel()
    {
        return in_array($this->level, $this->getSystemLevels());
    }

    /**
     * Create a new Groups Collection instance.
     *
     * @param  array  $models
     * @return GroupsCollection
     */
    public function newCollection(array $models = [])
    {
        return new GroupsCollection($models);
    }
}
