<?php

declare(strict_types=1);

namespace App\Services;

use AppConfig;
use ClientDetector;

class LogService {
  /** @var int Permissions du dossier */
  private const DIR_PERMISSIONS = 0750;

  /** @var int Permissions des fichiers */
  private const FILE_PERMISSIONS = 0640;

  public static function log(string $message, array $metadata = []): void {
    // Obtenir les informations client via ClientDetector
    $clientInfo = ClientDetector::getClientInfo();
    $clientType = $clientInfo['type'];
    
    $defaultMetadata = [
      'level' => 'info',
      'client' => [
        'ip' => $clientInfo['ip'],
        'browser' => $clientInfo['browser'],
        'os' => $clientInfo['os'],
        'screenResolution' => 'N/A',
        'userAgent' => $clientInfo['userAgent']
      ],
      'client_type' => $clientType
    ];
    
    // Si c'est une app mobile, ajouter l'identifiant de l'app
    if ($clientType === 'mobile' && isset($clientInfo['appIdentifier'])) {
      $defaultMetadata['app_identifier'] = $clientInfo['appIdentifier'];
    }
    
    // Ajouter les informations de session si disponibles
    if (session_status() === PHP_SESSION_ACTIVE) {
      if (isset($_SESSION['user_id'])) {
        $defaultMetadata['user_id'] = $_SESSION['user_id'];
      }
      if (isset($_SESSION['entity_id'])) {
        $defaultMetadata['entity_id'] = $_SESSION['entity_id'];
      }
      if (isset($_SESSION['operation_id'])) {
        $defaultMetadata['operation_id'] = $_SESSION['operation_id'];
      }
    }

    $metadata = array_merge_recursive($defaultMetadata, $metadata);

    $logData = [
      'metadata' => $metadata,
      'message' => $message
    ];

    try {
      // Récupérer la configuration de l'application
      $appConfig = AppConfig::getInstance();
      $appName = $appConfig->getName();
      
      // Récupérer l'environnement défini dans la configuration
      $environment = $appConfig->getEnvironment();
      
      // Définir le chemin du dossier logs à la racine du projet
      $logDir = __DIR__ . '/../../logs';
      
      // Créer le nom du fichier basé sur l'application et l'environnement
      // Format: geosector-production-2025-03-28.log, geosector-recette-2025-03-28.log, geosector-development-2025-03-28.log
      $filename = $logDir . '/' . $appName . '-' . $environment . '-' . date('Y-m-d') . '.log';

      // Créer le dossier logs s'il n'existe pas
      if (!is_dir($logDir)) {
        if (!mkdir($logDir, self::DIR_PERMISSIONS, true)) {
          error_log("Impossible de créer le dossier de logs: {$logDir}");
          return; // Sortir de la fonction si on ne peut pas créer le dossier
        }
      }
      
      // Vérifier si le dossier est accessible en écriture
      if (!is_writable($logDir)) {
        error_log("Le dossier de logs n'est pas accessible en écriture: {$logDir}");
        return; // Sortir de la fonction si on ne peut pas écrire dans le dossier
      }
    } catch (\Exception $e) {
      error_log("Erreur lors de la configuration des logs: " . $e->getMessage());
      return; // Sortir de la fonction en cas d'erreur
    }

    try {
      // Formater la ligne de log au format plat demandé
      // timestamp;browser.name@browser.version;os.name@os.version;client_type;$metadata;$message
      $timestamp = date('Y-m-d\TH:i:s');
      $browserInfo = $clientInfo['browser']['name'] . '@' . $clientInfo['browser']['version'];
      
      // Ne pas afficher l'OS s'il est unknown
      $osInfo = '';
      if ($clientInfo['os']['name'] !== 'unknown' && $clientInfo['os']['version'] !== 'unknown') {
        $osInfo = $clientInfo['os']['name'] . '@' . $clientInfo['os']['version'];
      }
      
      // Extraire le niveau de log
      $level = isset($metadata['level']) ? (is_array($metadata['level']) ? 'info' : $metadata['level']) : 'info';
      
      // Préparer les métadonnées supplémentaires (exclure celles déjà incluses dans le format)
      $additionalMetadata = [];
      
      // Ajouter user_id, entity_id et operation_id en premier s'ils existent
      $priorityKeys = ['user_id', 'entity_id', 'operation_id'];
      foreach ($priorityKeys as $key) {
        if (isset($metadata[$key]) && !is_array($metadata[$key])) {
          $additionalMetadata[$key] = $metadata[$key];
        }
      }
      
      // Ajouter les autres métadonnées
      foreach ($metadata as $key => $value) {
        if (!in_array($key, ['browser', 'os', 'client_type', 'side', 'version', 'level', 'environment', 'client']) 
            && !in_array($key, $priorityKeys)) {
          if (is_array($value)) {
            $additionalMetadata[$key] = json_encode($value, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
          } else {
            $additionalMetadata[$key] = $value;
          }
        }
      }
      
      // Joindre les métadonnées supplémentaires avec des virgules
      $metadataStr = !empty($additionalMetadata) ? implode(',', array_map(function($k, $v) {
        return $k . '=' . $v;
      }, array_keys($additionalMetadata), $additionalMetadata)) : '-';
      
      // Construire la ligne de log au format demandé
      $logLine = implode(';', [
        $timestamp,
        $browserInfo,
        $osInfo,
        $clientType,
        $level,
        $metadataStr,
        $message
      ]) . "\n";

      // Écrire dans le fichier avec gestion d'erreur et verrouillage
      if (file_put_contents($filename, $logLine, FILE_APPEND | LOCK_EX) === false) {
        error_log("Impossible d'écrire dans le fichier de logs: {$filename}");
      } else {
        // Appliquer les permissions au fichier
        @chmod($filename, self::FILE_PERMISSIONS);
      }
    } catch (\Exception $e) {
      error_log("Erreur lors de l'écriture des logs: " . $e->getMessage());
    }
  }

  public static function info(string $message, array $metadata = []): void {
    $metadata['level'] = 'info';
    self::log($message, $metadata);
  }

  public static function warning(string $message, array $metadata = []): void {
    $metadata['level'] = 'warning';
    self::log($message, $metadata);
  }

  public static function error(string $message, array $metadata = []): void {
    $metadata['level'] = 'error';
    self::log($message, $metadata);
  }
}
