<?php

namespace Ignite\Core\Auth;

use Illuminate\Contracts\Auth\Access\Authorizable;
use Illuminate\Contracts\Auth\Access\Gate;
use Illuminate\Contracts\Cache\Repository;
use Ignite\Core\Entities\Permission;
use Ignite\Core\Entities\User;

class Authorization
{
    const GOD_GROUP = 'admin';

    /**
     * @var Gate
     */
    private $gate;

    /**
     * @var Repository
     */
    private $cache;

    /**
     * @var string
     */
    private $cacheKey = 'ignite.permissions.cache';

    /**
     * The
     * @var \Illuminate\Support\Collection|null
     */
    private $memory;


    /**
     * Authorization constructor.
     *
     * @param Gate $gate
     * @param Repository $cache
     */
    public function __construct(Gate $gate, Repository $cache)
    {
        $this->gate = $gate;
        $this->cache = $cache;
    }

    /**
     * The stored permissions.
     *
     * @return \Illuminate\Support\Collection|mixed
     */
    public function getPermissions()
    {
        if (is_null($this->memory)) {
            $this->memory = $this->cache->remember($this->cacheKey, 15, function () {
                return Permission::with('groups')->get();
            });
        }

        return $this->memory;
    }

    /**
     * Register the permissions with the gate.
     *
     * @return $this
     */
    public function registerPermissions()
    {
        $this->gate->before(function (Authorizable $user, string $ability) {
            if ($user->hasGroup(static::GOD_GROUP)) {
                return true;
            }

            return $user->hasPermission($ability);
        });

        return $this;
    }

    /**
     * Forget the cached permissions.
     *
     * @return $this
     */
    public function forgetCachedPermissions()
    {
        $this->cache->forget($this->cacheKey);

        return $this;
    }

    /**
     * Forget the permissions.
     *
     * @return $this
     */
    public function forgetPermissions()
    {
        $this->forgetCachedPermissions();

        $this->memory = null;

        return $this;
    }
}
