<?php

namespace Fivable\Buildable\Models;

use Fivable\Buildable\Traits\HasMasks;
use Fivable\Buildable\Traits\HasMetas;
use Fivable\Scaffolding\Models\ScaffoldingUser;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Query\Builder;

class BuildableUser extends ScaffoldingUser
{
    use SoftDeletes, HasMetas, HasMasks;

    /* Columns that are mass-assignable */
    protected $fillable = ['email', 'password', 'remember_token', 'first_name', 'middle_name', 'last_name', 'role_mask'];
    /* Columns to convert to Carbon */
    protected $dates = ['created_at', 'updated_at', 'deleted_at'];
    /* Accessors to automatically populate */
    protected $appends = ['metas'];


    /** Relationships
     * ----------------*/

    /**
     * Get the BuildableActivities associated with this BuildableUser
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
     */
    public function buildable_activities()
    {
        return $this->hasMany('Fivable\Buildable\Models\BuildableActivity');
    }

    /**
     * Get the BuildablePages this BuildableUser has created
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
     */
    public function buildable_pages()
    {
        return $this->hasMany('Fivable\Buildable\Models\BuildablePage');
    }

    /**
     * Get the BuildablePosts this BuildableUser has created
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
     */
    public function buildable_posts()
    {
        return $this->hasMany('Fivable\Buildable\Models\BuildablePost');
    }



    /** CRUD Helpers
     * ----------------*/

    /**
     * @param BuildableUser $user
     * @return Builder|NULL
     */
    public static function indexFor(BuildableUser $user) : ?Builder
    {
        if ($user->isSuperadmin()) {
            return static::query()->withTrashed()->get();
        } else if ($user->isAdmin()) {
            return static::whereRaw('!(role_mask & 1)')->get();
        } else {
            return NULL;
        }
    }


    /** Status Helpers
     * ----------------*/

    /**
     * Return whether this BuildableUser has a role when passed a string
     * Return whether this BuildableUser has all roles ($operator=='and')
     * or has one of the given roles ($operator=='or') when passed an array
     * @param string/array $roles
     * @param string $operator
     * @return bool
     */
    public function hasRoles($roles, $operator = 'and') : bool
    {
        if (is_string($roles)) {
            return ('is' . ucfirst($roles))();
        } else if ($operator == 'or') {
            $matches = array_filter($roles, function($role) {
                return ('is' . ucfirst($role))();
            });
            return count($matches) > 0;
        } else if ($operator == 'and') {
            $matches = array_filter($roles, function($role) {
                return ('is' . ucfirst($role))();
            });
            return count($matches) == count($roles);
        }
    }

    /**
     * Determine if this BuildableUser is an Editor
     * @return bool
     */
    public function isEditor() : bool
    {
        return !!($this->role_mask & 4);
    }

    /**
     * Determine if this BuildableUser is an Admin
     * @return bool
     */
    public function isAdmin() : bool
    {
        return !!($this->role_mask & 2);
    }

    /**
     * Determine if this BuildableUser is a Super Admin
     * @return bool
     */
    public function isSuperadmin() : bool
    {
        return !!($this->role_mask & 1);
    }

    /**
     * Get this BuildableUser's highest role_mask bit
     * @return int
     */
    public function highestRoleMaskBit() : int
    {
        if ($this->isSuperadmin()) {
            return 1;
        } else if ($this->isAdmin()) {
            return 2;
        } else if ($this->isEditor()) {
            return 1;
        } else {
            return 0;
        }
    }

    /**
     * Get an array of all the bits in this BuildableUser's role_mask
     * @return array|NULL
     */
    public function roleMaskArray()
    {
        $masks = [];
        !$this->isSuperadmin() ?: array_push($masks, 1);
        !$this->isAdmin() ?: array_push($masks, 2);
        !$this->isEditor() ?: array_push($masks, 4);

        return empty($masks) ? NULL : $masks;
    }
}
