<?php

namespace App\Controller;

use App\Entity\AnalyticsUniqId;
use App\Message\AnalyticsMessage;
use App\Service\AnalyticsCryptoService;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\DependencyInjection\Attribute\Autowire;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Messenger\MessageBusInterface;
use Symfony\Component\Routing\Attribute\Route;

class AnalyticsController extends AbstractController
{
    #[Route('/t/{token}', name: 'app_analytics_track', methods: ['POST'])]
    public function track(
        string $token,
        #[Autowire(env: 'SECRET_ANALYTICS')] string $analyticsSecret,
        Request $request,
        AnalyticsCryptoService $crypto,
        EntityManagerInterface $em,
        MessageBusInterface $bus,
    ): Response {
        $expectedToken = substr(hash('sha256', $analyticsSecret.'_endpoint'), 0, 8);
        if (!hash_equals($expectedToken, $token)) {
            return new Response('', 404);
        }

        $body = $request->getContent();
        $envelope = json_decode($body, true);

        if (!$envelope || !isset($envelope['d'])) {
            return new Response('', 400);
        }

        $data = $crypto->decrypt($envelope['d']);
        if (null === $data) {
            return new Response('', 403);
        }

        $uid = $data['uid'] ?? null;
        $hash = $data['h'] ?? null;

        // No uid = create new visitor
        if (!$uid) {
            $visitor = $this->createVisitor($request, $data, $crypto, $em);

            $responseData = $crypto->encrypt([
                'uid' => $visitor->getUid(),
                'h' => $visitor->getHash(),
            ]);

            return new JsonResponse(['d' => $responseData]);
        }

        // Verify hash
        if (!$hash || !$crypto->verifyVisitorHash($uid, $hash)) {
            return new Response('', 403);
        }

        // setUser
        if (isset($data['setUser'])) {
            $bus->dispatch(new AnalyticsMessage($uid, 'set_user', ['userId' => (int) $data['setUser']]));

            return new Response('', 204);
        }

        // page_view
        $bus->dispatch(new AnalyticsMessage($uid, 'page_view', [
            'url' => $data['u'] ?? '/',
            'title' => $data['t'] ?? null,
            'referrer' => $data['r'] ?? null,
        ]));

        return new Response('', 204);
    }

    /** @param array<string, mixed> $data */
    private function createVisitor(
        Request $request,
        array $data,
        AnalyticsCryptoService $crypto,
        EntityManagerInterface $em,
    ): AnalyticsUniqId {
        $uid = sprintf('%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
            random_int(0, 0xFFFF), random_int(0, 0xFFFF),
            random_int(0, 0xFFFF),
            random_int(0, 0x0FFF) | 0x4000,
            random_int(0, 0x3FFF) | 0x8000,
            random_int(0, 0xFFFF), random_int(0, 0xFFFF), random_int(0, 0xFFFF),
        );
        $ua = $request->headers->get('User-Agent', '');

        $visitor = new AnalyticsUniqId();
        $visitor->setUid($uid);
        $visitor->setHash($crypto->generateVisitorHash($uid));
        $visitor->setIpHash(hash('sha256', $request->getClientIp() ?? ''));
        $visitor->setUserAgent(substr($ua, 0, 512));
        $visitor->setScreenWidth(isset($data['sw']) ? (int) $data['sw'] : null);
        $visitor->setScreenHeight(isset($data['sh']) ? (int) $data['sh'] : null);
        $visitor->setLanguage(isset($data['l']) ? substr((string) $data['l'], 0, 10) : null);
        $visitor->setDeviceType(AnalyticsUniqId::parseDeviceType($ua));
        $visitor->setOs(AnalyticsUniqId::parseOs($ua));
        $visitor->setBrowser(AnalyticsUniqId::parseBrowser($ua));

        $em->persist($visitor);
        $em->flush();

        return $visitor;
    }
}
