<?php

/*
 * This file is part of Anis Server.
 *
 * (c) Laboratoire d'Astrophysique de Marseille / CNRS
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
declare(strict_types=1);

namespace App\Action;

use Doctrine\ORM\EntityManagerInterface;
use Psr\Http\Message\ServerRequestInterface;
use Slim\Exception\HttpUnauthorizedException;
use Slim\Exception\HttpForbiddenException;

/**
 * @author François Agneray <francois.agneray@lam.fr>
 * @package App\Action
 */
abstract class AbstractAction
{
    /**
     * The EntityManager is the central access point to Doctrine ORM functionality
     *
     * @var EntityManagerInterface
     */
    protected $em;

    /**
     * Create the classe before call __invoke to execute the action
     *
     * @param EntityManagerInterface $em Doctrine Entity Manager Interface
     */
    public function __construct(EntityManagerInterface $em)
    {
        $this->em = $em;
    }

    /**
     * @param string $field
     * @param array  $parsedBody
     *
     * @return string true if field is empty or false else
     */
    protected function isEmptyField(string $field, array $parsedBody): bool
    {
        return !isset($parsedBody[$field]);
    }

    /**
     * @param ServerRequestInterface $request     PSR-7 This object represents the HTTP request
     * @param string                 $datasetName
     * @param array                  $adminRoles
     */
    protected function verifyDatasetAuthorization(
        ServerRequestInterface $request,
        string $datasetName,
        array $adminRoles
    ) {
        $token = $request->getAttribute('token');
        if (!$token) {
            // The user is not connected (401)
            throw new HttpUnauthorizedException($request);
        }
        $roles = $token->realm_access->roles;
        if (!$this->isAdmin($adminRoles, $roles)) {
            $qb = $this->em->createQueryBuilder();
            $qb->select('d.name')
                ->from('App\Entity\Group', 'g')
                ->join('g.datasets', 'd')
                ->where($qb->expr()->in('g.role', $roles))
                ->andWhere($qb->expr()->eq('d.name', ':dname'));
            $qb->setParameter('dname', $datasetName);
            $r = $qb->getQuery()->getResult();
            if (count($r) < 1) {
                throw new HttpForbiddenException(
                    $request,
                    'You do not have the permission to access the dataset : ' . $datasetName
                );
            }
        }
    }

    /**
     * @param ServerRequestInterface $request      PSR-7 This object represents the HTTP request
     * @param string                 $instanceName
     * @param array                  $adminRoles
     */
    protected function verifyInstanceAuthorization(
        ServerRequestInterface $request,
        string $instanceName,
        array $adminRoles
    ) {
        $token = $request->getAttribute('token');
        if (!$token) {
            // The user is not connected (401)
            throw new HttpUnauthorizedException($request);
        }
        $roles = $token->realm_access->roles;
        if (!$this->isAdmin($adminRoles, $roles)) {
            $qb = $this->em->createQueryBuilder();
            $qb->select('i.name')
                ->from('App\Entity\InstanceGroup', 'ig')
                ->join('ig.instances', 'i')
                ->where($qb->expr()->in('ig.role', $roles))
                ->andWhere($qb->expr()->eq('i.name', ':iname'));
            $qb->setParameter('iname', $instanceName);
            $r = $qb->getQuery()->getResult();
            if (count($r) < 1) {
                throw new HttpForbiddenException(
                    $request,
                    'You do not have the permission to access the instance : ' . $instanceName
                );
            }
        }
    }

    protected function isAdmin(array $adminRoles, $roles)
    {
        $admin = false;
        for ($i = 0; $i < count($adminRoles); $i++) {
            $admin = in_array($adminRoles[$i], $roles);
            if ($admin) {
                break;
            }
        }
        return $admin;
    }
}