<?php

namespace App\Core\Audit\Services;

use App\Core\Audit\Models\AuditLogModel;
use App\Core\Auth\Models\UserModel;

class AuditService
{
    public function log(string $action, ?string $entityType = null, ?string $entityId = null, ?string $description = null): void
    {
        $request = service('request');

        (new AuditLogModel())->insert([
            'user_id' => session('core_user_id'),
            'action' => $action,
            'entity_type' => $entityType,
            'entity_id' => $entityId,
            'description' => $description,
            'ip_address' => method_exists($request, 'getIPAddress') ? $request->getIPAddress() : null,
            'user_agent' => substr((string) ($request->getUserAgent() ?? ''), 0, 255),
            'created_at' => date('Y-m-d H:i:s'),
        ]);
    }

    public function getRecentLogs(int $limit = 50): array
    {
        return $this->enrich((new AuditLogModel())->orderBy('created_at', 'DESC')->findAll($limit));
    }

    public function getLogsByUser(int $userId, int $limit = 50): array
    {
        return $this->enrich((new AuditLogModel())->where('user_id', $userId)->orderBy('created_at', 'DESC')->findAll($limit));
    }

    public function getLogsByEntity(string $entityType, string $entityId, int $limit = 50): array
    {
        $logs = (new AuditLogModel())
            ->where('entity_type', $entityType)
            ->where('entity_id', $entityId)
            ->orderBy('created_at', 'DESC')
            ->findAll($limit);

        return $this->enrich($logs);
    }

    private function enrich(array $logs): array
    {
        $userIds = [];
        foreach ($logs as $log) {
            if (! empty($log['user_id'])) {
                $userIds[] = (int) $log['user_id'];
            }

            if (($log['entity_type'] ?? '') === 'user' && ! empty($log['entity_id'])) {
                $userIds[] = (int) $log['entity_id'];
            }
        }

        $users = $this->userLabels(array_values(array_unique($userIds)));

        foreach ($logs as &$log) {
            $actorId = isset($log['user_id']) ? (int) $log['user_id'] : 0;
            $entityType = (string) ($log['entity_type'] ?? '');
            $entityId = (string) ($log['entity_id'] ?? '');

            $log['user_label'] = $actorId > 0 ? ($users[$actorId] ?? ('Utilisateur #' . $actorId)) : '-';
            $log['entity_label'] = $this->entityLabel($entityType, $entityId, $users);
        }

        return $logs;
    }

    private function userLabels(array $userIds): array
    {
        if ($userIds === []) {
            return [];
        }

        $labels = [];
        $users = (new UserModel())->whereIn('id', $userIds)->findAll();

        foreach ($users as $user) {
            $name = trim((string) ($user['firstname'] ?? '') . ' ' . (string) ($user['lastname'] ?? ''));
            $labels[(int) $user['id']] = $name !== '' ? $name : (string) $user['email'];
        }

        return $labels;
    }

    private function entityLabel(string $entityType, string $entityId, array $users): string
    {
        if ($entityType === '' && $entityId === '') {
            return '-';
        }

        if ($entityType === 'user' && $entityId !== '') {
            return $users[(int) $entityId] ?? ('Utilisateur #' . $entityId);
        }

        return trim($entityType . ' #' . $entityId, ' #');
    }
}
