<?php
namespace App\Middleware;

use App\Action\Logout;
use App\Authentication\AggregateAuth;
use Firebase\JWT\ExpiredException;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Slim\Flash\Messages;
use Zend\Authentication\Result;
use Zend\Diactoros\Response\RedirectResponse;
use Zend\Expressive\Router\RouteResult;

/**
 * Class Authentication
 * @package App\Middleware
 */
class Authentication
{
    /**
     * @var AggregateAuth
     */
    protected $auth;

    /**
     * @var Logout
     */
    protected $logoutAction;

    /**
     * Constructor.
     *
     * @param AggregateAuth $auth
     * @param Logout $logoutAction
     */
    public function __construct(AggregateAuth $auth, Logout $logoutAction)
    {
        $this->auth= $auth;
        $this->logoutAction = $logoutAction;
    }

    /**
     * Invoker.
     *
     * @param ServerRequestInterface $request
     * @param ResponseInterface $response
     * @param callable|null $next
     * @return ResponseInterface
     * @throws \Exception
     */
    public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next = null)
    {
        /** @var RouteResult $routeResult */
        $routeResult = $request->getAttribute(RouteResult::class);
        $matchedRouteName = null;
        if ($routeResult) {
            $matchedRouteName = $routeResult->getMatchedRouteName();
        }
        if (! ($request->getMethod() == 'POST' && in_array($matchedRouteName, ['login', 'adm.login', 'register', 'logout']))) {
            $cookie = $request->getCookieParams();
            $this->auth->setCookie($cookie);
            /** @var Result $result */
            try {
                $result = $this->auth->authenticate();
                if (!$result->isValid()) {
                    /** @var Messages $flash */
                    $flash = $request->getAttribute('flash');
                    foreach ($result->getMessages() as $message) {
                        $flash->addMessage('error', $message);
                    }
                    if ($result->getCode() == Result::FAILURE_IDENTITY_NOT_FOUND) {
                        $resultResponse = ($this->logoutAction)($request, $response);
                    }
                }
            } catch (ExpiredException $e){
                $resultResponse = new RedirectResponse('/');
                $this->auth->clearIdentity();
                $resultResponse = $this->auth->clearCookie($request, $resultResponse);

            } catch (\Exception $e) {
                /** @var Messages $flash */
                $flash = $request->getAttribute('flash');
                $flash->addMessage('error', $e->getMessage());
                $resultResponse = new RedirectResponse('/');
            }
        }

        if (isset($resultResponse)) {
            return $resultResponse;
        }

        return $next($request, $response);
    }

}