<?php

declare(strict_types=1);

namespace App\Service;

use App\Entity\AuditLog;
use App\Entity\Employee;
use App\Entity\User;
use DateTimeImmutable;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\SecurityBundle\Security;
use Symfony\Component\HttpFoundation\RequestStack;

readonly class AuditLogger
{
    public function __construct(
        private EntityManagerInterface $entityManager,
        private Security $security,
        private RequestStack $requestStack,
        private UserAgentParser $userAgentParser,
    ) {}

    public function log(
        ?Employee $employee,
        string $action,
        string $entityType,
        ?int $entityId,
        string $description,
        ?array $changes = null,
        ?DateTimeImmutable $affectedDate = null,
    ): void {
        $user     = $this->security->getUser();
        $username = $user instanceof User ? $user->getUsername() : 'system';

        $request   = $this->requestStack->getCurrentRequest();
        $ipAddress = null;
        $userAgent = null;
        $deviceId  = null;

        if (null !== $request) {
            $ipAddress = $request->getClientIp();
            $userAgent = $request->headers->get('User-Agent');
            $deviceId  = $request->headers->get('X-Device-Id');
            // The device id comes from an untrusted client header; cap it to the column width.
            if (null !== $deviceId) {
                $deviceId = mb_substr($deviceId, 0, 64);
            }
            // The user agent comes from an untrusted client header; cap it to prevent storage bloat.
            if (null !== $userAgent) {
                $userAgent = mb_substr($userAgent, 0, 1024);
            }
        }

        $auditLog = new AuditLog();
        $auditLog
            ->setEmployee($employee)
            ->setUsername($username)
            ->setAction($action)
            ->setEntityType($entityType)
            ->setEntityId($entityId)
            ->setDescription($description)
            ->setChanges($changes)
            ->setAffectedDate($affectedDate)
            ->setIpAddress($ipAddress)
            ->setUserAgent($userAgent)
            ->setDeviceLabel($this->userAgentParser->parse($userAgent))
            ->setDeviceId($deviceId)
        ;

        $this->entityManager->persist($auditLog);
    }
}
