<?php

namespace App\Controller;

use App\Message\MailgunEventMessage;
use Cake\Chronos\Chronos;
use FOS\RestBundle\Controller\Annotations as Rest;
use FOS\RestBundle\Controller\FOSRestController;
use FOS\RestBundle\View\View;
use Psr\Log\LoggerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Messenger\MessageBusInterface;

class MailgunController extends FOSRestController
{
    /**
     * @var LoggerInterface
     */
    private $logger;
    /**
     * @var MessageBusInterface
     */
    private $messageBus;

    public function __construct(LoggerInterface $logger, MessageBusInterface $messageBus)
    {
        $this->logger = $logger;
        $this->messageBus = $messageBus;
    }

    /**
     * @Rest\Post("/webhook/mc5ecg2v1amc")
     *
     * @return View
     */
    public function postDelivered(Request $request): View
    {
        $signature = $request->get('signature');
        if (!$this->verify('key-420028bde51b862ccb07fa1aa176f76e', $signature['token'], $signature['timestamp'], $signature['signature'])) {
            return View::create([], Response::HTTP_NOT_ACCEPTABLE);
        }

        try {
            $message = $this->parseRequest($request);
        } catch (\Exception $e) {
            $this->logger->error("Couldn't read data from Mailgun", ['errorMessage' => $e->getMessage()]);

            return View::create([], Response::HTTP_NOT_ACCEPTABLE);
        }

        $this->messageBus->dispatch($message);

        return View::create([], Response::HTTP_OK);
    }

    private function verify(string $apiKey, $token, $timestamp, $signature)
    {
        //check if the timestamp is fresh
        if (abs(time() - $timestamp) > 15) {
            return false;
        }

        //returns true if signature is valid
        return hash_hmac('sha256', $timestamp.$token, $apiKey) === $signature;
    }

    /**
     * @param Request $request
     *
     * @return MailgunEventMessage
     *
     * @throws \Exception
     */
    private function parseRequest(Request $request): MailgunEventMessage
    {
        $data = $request->get('event-data');

        if (!$data) {
            throw new \Exception('Event data not found');
        }

        if (array_key_exists('timestamp', $data)) {
            $timestamp = $data['timestamp'];
        } else {
            throw new \Exception('Timestamp not found');
        }

        $timestamp = Chronos::createFromTimestamp((int) $timestamp)->toMutable();

        if (array_key_exists('event', $data)) {
            $event = $data['event'];
        } else {
            throw new \Exception('Event not found');
        }

        if (array_key_exists('user-variables', $data)) {
            $userVariables = $data['user-variables'];
        } else {
            throw new \Exception('User variables not found');
        }

        if (array_key_exists('message-id', $userVariables)) {
            $messageId = $userVariables['message-id'];
        } else {
            throw new \Exception('User variables not found');
        }

        if (is_numeric($messageId)) {
            $messageId = (int) $messageId;
        } else {
            throw new \Exception('Message id is not a number');
        }

        return new MailgunEventMessage($messageId, $event, $timestamp);
    }
}
