<?php 
 
namespace App\Security\Voter; 
 
use App\Entity\DeviceGroup; 
use App\Entity\Plan; 
use App\Entity\User; 
use App\Entity\Workspace; 
use App\Repository\DeviceGroupRepository; 
use App\Repository\UserRepository; 
use App\Utils\Commons; 
use Symfony\Component\Security\Core\Security; 
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; 
use Symfony\Component\Security\Core\Authorization\Voter\Voter; 
 
class PlanPricingVoter extends Voter 
{ 
    /** 
     * @var UserRepository 
     */ 
    private $userRepository; 
 
    /** 
     * @var DeviceGroupRepository 
     */ 
    private $deviceGroupRepository; 
 
    /** 
     * @var Commons 
     */ 
    private $commons; 
 
    /** 
     * @var array 
     */ 
    private $permissions; 
 
    private $security; 
 
    /** 
     * Constructor. 
     * @param UserRepository $userRepository 
     * @param Security $security 
     */ 
    public function __construct( 
        Commons $commons, 
        UserRepository $userRepository, 
        DeviceGroupRepository $deviceGroupRepository, 
        Security $security 
    ) 
    { 
        $this->permissions = []; 
        $this->commons = $commons; 
        $this->security = $security; 
        $this->userRepository = $userRepository; 
        $this->deviceGroupRepository = $deviceGroupRepository; 
    } 
 
    // these strings are just invented: you can use anything 
    const VIEW_PLAN_USER_GROUP = 'VIEW_PLAN_USER_GROUP'; 
    const VIEW_PLAN_SANDBOX_MODE = 'VIEW_PLAN_SANDBOX_MODE'; 
    const VIEW_PLAN_DATA_EXPORT = 'VIEW_PLAN_DATA_EXPORT'; 
    const VIEW_PLAN_2FA_AUTH = 'VIEW_PLAN_2FA_AUTH'; 
    const VIEW_PLAN_INDIVIDUAL_DEVICE_FIELDS = 'VIEW_PLAN_INDIVIDUAL_DEVICE_FIELDS'; 
    const VIEW_PLAN_SCHEDULED_ROLLOUTS = 'VIEW_PLAN_SCHEDULED_ROLLOUTS'; 
    const VIEW_PLAN_BLOCKCHAIN_DEVICE_LOG = 'VIEW_PLAN_BLOCKCHAIN_DEVICE_LOG'; 
    const VIEW_PLAN_NAMED_USERS = 'VIEW_PLAN_NAMED_USERS'; 
    const VIEW_PLAN_MAPBOX = 'VIEW_PLAN_MAPBOX'; 
 
    protected function supports($attribute, $subject) 
    { 
        // if the attribute isn't one we support, return false 
        if (!in_array($attribute, [ 
                self::VIEW_PLAN_USER_GROUP, 
                self::VIEW_PLAN_SANDBOX_MODE, 
                self::VIEW_PLAN_DATA_EXPORT, 
                self::VIEW_PLAN_2FA_AUTH, 
                self::VIEW_PLAN_INDIVIDUAL_DEVICE_FIELDS, 
                self::VIEW_PLAN_SCHEDULED_ROLLOUTS, 
                self::VIEW_PLAN_BLOCKCHAIN_DEVICE_LOG, 
                self::VIEW_PLAN_NAMED_USERS, 
                self::VIEW_PLAN_MAPBOX, 
        ])) { 
            return false; 
        } 
 
        // only vote on `User` objects 
//        if (!$subject instanceof User) { 
//            return false; 
//        } 
 
        return true; 
    } 
 
    protected function voteOnAttribute($attribute, $subject, TokenInterface $token) 
    { 
        if ($this->security->isGranted('ROLE_BACKEND_USER')) { 
            return true; 
        } 
 
        $user = $token->getUser(); 
        $this->permissions = $this->commons->getUserPermissions($user); 
 
        if (!$user instanceof User) { 
            // the user must be logged in; if not, deny access 
            return false; 
        } 
 
        $plan = $token->getUser()->getWorkSpace()->getPlan(); 
 
        switch ($attribute) { 
            case self::VIEW_PLAN_USER_GROUP: 
                return $this->canViewUserGroup($plan); 
            case self::VIEW_PLAN_SANDBOX_MODE: 
                return $this->canViewSandBoxMode($plan); 
            case self::VIEW_PLAN_DATA_EXPORT: 
                return $this->canViewDataExport($plan); 
            case self::VIEW_PLAN_2FA_AUTH: 
                return $this->canView2FAAuth($plan); 
            case self::VIEW_PLAN_INDIVIDUAL_DEVICE_FIELDS: 
                return $this->canViewIndividualDeviceField($plan); 
            case self::VIEW_PLAN_SCHEDULED_ROLLOUTS: 
                return $this->canViewScheduledRollouts($plan); 
            case self::VIEW_PLAN_BLOCKCHAIN_DEVICE_LOG: 
                return $this->canViewBlockchainDeviceLog($plan); 
            case self::VIEW_PLAN_NAMED_USERS: 
                return $this->canViewNamedUsers($user->getWorkspace(), $user); 
            case self::VIEW_PLAN_MAPBOX: 
                return $this->canViewMapbox($plan); 
; 
        } 
 
        throw new \LogicException('This code should not be reached!'); 
    } 
 
    private function canViewUserGroup(Plan $plan) 
    { 
        return $plan->getUserGroups(); 
    } 
 
    private function canViewSandBoxMode(Plan $plan) 
    { 
        return $plan->getSandboxMode(); 
    } 
 
    private function canViewDataExport(Plan $plan) 
    { 
        return $plan->getDataExport(); 
    } 
 
    private function canView2FAAuth(Plan $plan) 
    { 
        return $plan->getAuth2fa(); 
    } 
 
    private function canViewIndividualDeviceField(Plan $plan) 
    { 
        return $plan->getIndividualDeviceFields(); 
    } 
 
    private function canViewScheduledRollouts(Plan $plan) 
    { 
        return $plan->getScheduledRollouts(); 
    } 
 
    private function canViewBlockchainDeviceLog(Plan $plan) 
    { 
        return $plan->getBlockchainDeviceLog(); 
    } 
 
    private function canViewNamedUsers(Workspace $workspace, User $user) 
    { 
        $users = $this->userRepository->findAllUsersByRole($user->getId(), $workspace->getId())->getQuery()->getArrayResult(); 
        $flag = false; 
 
        if(count($users) < $workspace->getPlan()->getNamedUsers()){ 
            $flag = true; 
        } 
 
        return $flag; 
    } 
 
    private function canViewMapbox(Plan $plan) 
    { 
//        if (!$plan->getMapBox()) { 
//            return false; 
//        } 
// 
//        if ($this->security->isGranted('ROLE_ADMIN')) { 
//            return true; 
//        } 
// 
//        if (array_key_exists('deviceGroup', $this->permissions)) { 
//            if (in_array('Edit', $this->permissions['deviceGroup'])) { 
//                return true; 
//            } 
//        } 
 
        return $plan->getMapBox(); 
    } 
 
    /** 
     * @param User|null $user 
     * @param $subject 
     * @return bool 
     */ 
    private function isOwner(User $user, $subject): bool 
    { 
        if (!is_object($subject)) { 
            $subject = $this->deviceGroupRepository->findOneBy(["id" => intval($subject)]); 
        } 
        if (!$subject instanceof DeviceGroup) { 
            return false; 
        } 
 
        return $user->getWorkspace()->getId() === $subject->getWorkspace()->getId(); 
    } 
 
    /** Return True if have Edit Permission else return false 
     * @return bool 
     */ 
    private function canEdit(): bool 
    { 
 
    } 
}