<?php

declare(strict_types=1);


class LogController {
  private const REQUIRED_FIELDS = [
    'metadata' => [
      'side',
      'version',
      'level',
      'timestamp',
      'environment',
      'client' => [
        'ip',
        'browser' => ['name', 'version'],
        'os' => ['name', 'version'],
        'screenResolution',
        'userAgent'
      ]
    ],
    'message'
  ];

  public function index(): void {
    try {
      // Récupérer la configuration de l'application
      $appConfig = AppConfig::getInstance();
      $appName = $appConfig->getName();
      $clientType = ClientDetector::getClientType();

      // Récupérer et décoder le JSON
      $data = json_decode(file_get_contents('php://input'), true);

      // Vérifier si le JSON est valide
      if (json_last_error() !== JSON_ERROR_NONE) {
        throw new \Exception('Invalid JSON format');
      }

      // Valider la structure des données
      $this->validateData($data);

      // Ajouter le type de client aux métadonnées
      $data['metadata']['client_type'] = $clientType;

      // Si c'est une app mobile, ajouter l'identifiant de l'app
      if ($clientType === 'mobile') {
        $data['metadata']['app_identifier'] = ClientDetector::getAppIdentifier();
      }


      // Définir le chemin du dossier logs à la racine du projet
      $logDir = __DIR__ . '/../../logs';

      // Créer le dossier logs s'il n'existe pas
      if (!is_dir($logDir)) {
        if (!mkdir($logDir, 0777, true)) {
          throw new \Exception("Impossible de créer le dossier de logs: {$logDir}");
        }
        // S'assurer que les permissions sont correctes
        chmod($logDir, 0777);
      }
      
      // Vérifier si le dossier est accessible en écriture
      if (!is_writable($logDir)) {
        throw new \Exception("Le dossier de logs n'est pas accessible en écriture: {$logDir}");
      }

      // Récupérer l'environnement défini dans la configuration
      $environment = $appConfig->getEnvironment();
      
      // Créer le nom du fichier basé sur l'environnement et la date
      // Format: geosector-production-2025-03-28.log, geosector-recette-2025-03-28.log, geosector-development-2025-03-28.log
      $filename = $logDir . '/geosector-' . $environment . '-' . date('Y-m-d') . '.log';

      // 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 = $data['metadata']['client']['browser']['name'] . '@' . $data['metadata']['client']['browser']['version'];
      $osInfo = $data['metadata']['client']['os']['name'] . '@' . $data['metadata']['client']['os']['version'];
      $clientType = $data['metadata']['client_type'];
      
      // Extraire le niveau de log
      $level = isset($data['metadata']['level']) ? (is_array($data['metadata']['level']) ? 'info' : $data['metadata']['level']) : 'info';
      
      // Préparer les métadonnées supplémentaires (exclure celles déjà incluses dans le format et les informations client)
      $additionalMetadata = [];
      foreach ($data['metadata'] as $key => $value) {
        // Exclure les informations client, type client, side, version, level et environment
        if (!in_array($key, ['client', 'client_type', 'side', 'version', 'level', 'environment'])) {
          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,
        $data['message']
      ]) . "\n";

      // Écrire dans le fichier avec vérification complète
      if (file_put_contents($filename, $logLine, FILE_APPEND) === false) {
        throw new \Exception("Impossible d'écrire dans le fichier de logs: {$filename}");
      }

      // Retourner 204 No Content en cas de succès
      http_response_code(204);
    } catch (\Exception $e) {
      Response::json([
        'success' => false,
        'message' => $e->getMessage()
      ], 400);
    }
  }

  private function validateData($data): void {
    if (!isset($data['metadata']) || !isset($data['message'])) {
      throw new \Exception('Missing required root fields');
    }

    // Valider la structure metadata
    foreach (self::REQUIRED_FIELDS['metadata'] as $key => $value) {
      if (is_array($value)) {
        if (!isset($data['metadata'][$key])) {
          throw new \Exception("Missing metadata field: {$key}");
        }
        foreach ($value as $subKey => $subValue) {
          if (is_array($subValue)) {
            foreach ($subValue as $field) {
              if (!isset($data['metadata'][$key][$subKey][$field])) {
                throw new \Exception("Missing metadata field: {$key}.{$subKey}.{$field}");
              }
            }
          } else {
            if (!isset($data['metadata'][$key][$subValue])) {
              throw new \Exception("Missing metadata field: {$key}.{$subValue}");
            }
          }
        }
      } else {
        if (!isset($data['metadata'][$value])) {
          throw new \Exception("Missing metadata field: {$value}");
        }
      }
    }
  }
}
