<?php

declare(strict_types=1);

/**
 * Configuration de l'application Geosector
 * 
 * Ce fichier contient la configuration de l'application Geosector pour les trois environnements :
 * - Production (app3.geosector.fr)
 * - Recette (rapp.geosector.fr)
 * - Développement (dapp.geosector.fr)
 * 
 * Il inclut les paramètres de base de données, les informations SMTP,
 * les clés de chiffrement et les configurations des services externes (Mapbox, Stripe, SMS OVH).
 */
class AppConfig {
  private static ?self $instance = null;
  private array $headers;
  private array $config;
  private string $currentHost;
  private string $clientIp;

  private function __construct() {
    // Récupération du host directement depuis SERVER_NAME ou HTTP_HOST
    $this->currentHost = $_SERVER['SERVER_NAME'] ?? $_SERVER['HTTP_HOST'] ?? '';

    // Si on est en CLI (CRON, scripts), tenter de détecter via le marqueur d'environnement
    if (empty($this->currentHost) && php_sapi_name() === 'cli') {
      $markerFile = __DIR__ . '/../../.env_marker';
      if (file_exists($markerFile)) {
        $envMarker = trim(file_get_contents($markerFile));
        switch ($envMarker) {
          case 'production':
            $this->currentHost = 'app3.geosector.fr';
            break;
          case 'recette':
            $this->currentHost = 'rapp.geosector.fr';
            break;
          case 'development':
            $this->currentHost = 'dapp.geosector.fr';
            break;
        }
      }
    }

    // Récupérer les autres en-têtes pour une utilisation ultérieure si nécessaire
    // getallheaders() n'existe pas en CLI, donc on vérifie
    $this->headers = function_exists('getallheaders') ? getallheaders() : [];

    // Déterminer l'adresse IP du client
    $this->clientIp = $this->getClientIpAddress();

    $this->initConfig();
    $this->validateApp();
  }

  public static function getInstance(): self {
    if (self::$instance === null) {
      self::$instance = new self();
    }
    return self::$instance;
  }

  private function initConfig(): void {
    // Configuration de base commune à tous les environnements
    $baseConfig = [
      'name' => 'geosector',
      'encryption_key' => 'Qga2M8Ov6tyx2fIQRWHQ1U6oMK/bAFdTL7A8VRtiDhk=',
      'smtp' => [
        'host' => 'barbotte.o2switch.net',
        'auth' => true,
        'user' => 'noreply@geosector.fr',
        'pass' => '@G83^[OMSo^Q',
        'secure' => 'ssl',
        'port' => 465,
      ],
      'email' => [
        'from' => 'noreply@geosector.fr',
        'contact' => 'contact@geosector.fr',
        'hourly_limit' => 1500, // Limite de 1500 emails/heure comme mentionné dans le cahier des charges
      ],
      'mapbox' => [
        'api_key' => '', // À remplir avec la clé API Mapbox
      ],
      // NOTE : La configuration Stripe est définie par environnement (voir plus bas)
      // - DEV : Clés TEST Pierre (développement)
      // - REC : Clés TEST Client (recette)
      // - PROD : Clés LIVE Client (production)
      'sms' => [
        'provider' => 'ovh', // Comme mentionné dans le cahier des charges
        'api_key' => '', // À remplir avec la clé API SMS OVH
        'api_secret' => '', // À remplir avec le secret API SMS OVH
      ],
      'backup' => [
        'encryption_key' => 'K8mN2pQ5rT9wX3zA6bE1fH4jL7oS0vY2', // Clé de 32 caractères pour AES-256
        'compression' => true,
        'compression_level' => 6,
        'cipher' => 'AES-256-CBC'
      ],
    ];

    // Configuration PRODUCTION
    $this->config['app3.geosector.fr'] = array_merge($baseConfig, [
      'env' => 'production',
      'database' => [
        'host' => '13.23.33.4',  // Container maria4 sur IN4 (51.159.7.190)
        'name' => 'pra_geo',
        'username' => 'pra_geo_user',
        'password' => 'd2jAAGGWi8fxFrWgXjOA',
      ],
      'addresses_database' => [
        'host' => '13.23.33.4',  // Container maria4 sur IN4
        'name' => 'adresses',
        'username' => 'adr_geo_user',
        'password' => 'd66,AdrGeoPrd.User',
      ],
      'buildings_database' => [
        'host' => '13.23.33.4',  // Container maria4 sur IN4
        'name' => 'batiments',
        'username' => 'adr_geo_user',
        'password' => 'd66,AdrGeoPrd.User',
      ],
      // Configuration Stripe PRODUCTION - Clés LIVE du CLIENT
      'stripe' => [
        'public_key_test' => 'pk_test_XXXXXX', // Non utilisé en PROD
        'secret_key_test' => 'sk_test_XXXXXX', // Non utilisé en PROD
        'public_key_live' => 'pk_live_51S5oMd1tQE0jBEomdRW82RvqAFjmqN45szbU08t8nDk4yc5QnhAJtPrP1IZJB48fF1pePUqrGsM5vyAhhoaWCT8d00nh51QIsU',
        'secret_key_live' => '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',
        'webhook_secret_test' => 'whsec_test_XXXXXXXXXXXX',
        'webhook_secret_live' => 'whsec_gFnA6pR92RLdbAS2T6CSC18xsSdNBZHR',
        'api_version' => '2025-08-27.basil',
        'application_fee_percent' => 0,
        'application_fee_minimum' => 0,
        'mode' => 'live', // ← MODE LIVE pour la production
      ],
    ]);

    // Configuration RECETTE
    $this->config['rapp.geosector.fr'] = array_merge($baseConfig, [
      'env' => 'recette',
      'database' => [
        // Configuration maria3 activée (migration effectuée le 16/10/2025)
        'host' => '13.23.33.4',  // Container maria3 sur IN3
        'name' => 'rca_geo',
        'username' => 'rca_geo_user',
        'password' => 'UPf3C0cQ805LypyM71iW',

        // Configuration AVANT migration (base locale dans rca-geo) - DÉSACTIVÉE
        // 'host' => 'localhost',
        // 'name' => 'geo_app',
        // 'username' => 'geo_app_user_rec',
        // 'password' => 'UPf3C0cQ805LypyM71iW',
      ],
      'addresses_database' => [
        'host' => '13.23.33.4',  // Container maria3 sur IN3
        'name' => 'adresses',
        'username' => 'adr_geo_user',
        'password' => 'd66,AdrGeoRec.User',
      ],
      'buildings_database' => [
        'host' => '13.23.33.4',  // Container maria3 sur IN3
        'name' => 'batiments',
        'username' => 'adr_geo_user',
        'password' => 'd66,AdrGeoRec.User',
      ],
      // Configuration Stripe RECETTE - Clés TEST du CLIENT
      'stripe' => [
        'public_key_test' => 'pk_test_51S5oN00EZ9a0jvy2VSPjAYyCiJWci8lwfuakc0wpStt5YWq8RlQWyliICYIWHwTaejeW8uMSKA6KTfsfUAOvjRi500XPXWRFhJ',
        'secret_key_test' => 'sk_test_51S5oN00EZ9a0jvy2paTcHY91Alh5QIMJLJZJGJ188jXqte5AkxwymbLoLDiLcCn0uQH41WC75UM03HPDDp04gl7h00wfno08gE',
        'public_key_live' => 'pk_live_XXXXXX', // Non utilisé en REC
        'secret_key_live' => 'sk_live_XXXXXX', // Non utilisé en REC
        'webhook_secret_test' => 'whsec_avExshr0MeWTI7wXP8478XVUkrbYG8hs',
        'webhook_secret_live' => 'whsec_live_XXXXXXXXXXXX',
        'api_version' => '2025-08-27.basil',
        'application_fee_percent' => 0,
        'application_fee_minimum' => 0,
        'mode' => 'test', // ← MODE TEST pour la recette
      ],
    ]);

    // Configuration DÉVELOPPEMENT
    $this->config['dapp.geosector.fr'] = array_merge($baseConfig, [
      'env' => 'development',
      'database' => [
        // Configuration maria3 (migration effectuée le 07/10/2025)
        'host' => '13.23.33.4',  // Container maria3 sur IN3
        'name' => 'dva_geo',
        'username' => 'dva_geo_user',
        'password' => 'CBq9tKHj6PGPZuTmAHV7',

        // Configuration locale AVANT migration (sauvegarde)
        // 'host' => 'localhost',
        // 'name' => 'geo_app',
        // 'username' => 'geo_app_user_dev',
        // 'password' => 'CBq9tKHj6PGPZuTmAHV7',
      ],
      'addresses_database' => [
        'host' => '13.23.33.4',  // Container maria3 sur IN3
        'name' => 'adresses',
        'username' => 'adr_geo_user',
        'password' => 'd66,AdrGeoDev.User',
      ],
      'buildings_database' => [
        'host' => '13.23.33.4',  // Container maria3 sur IN3
        'name' => 'batiments',
        'username' => 'adr_geo_user',
        'password' => 'd66,AdrGeoDev.User',
      ],
      // Configuration Stripe DÉVELOPPEMENT - Clés TEST de Pierre (plateforme de test existante)
      'stripe' => [
        'public_key_test' => 'pk_test_51QwoVN00pblGEgsXkf8qlXmLGEpxDQcG0KLRpjrGLjJHd7AVZ4Iwd6ChgdjO0w0n3vRqwNCEW8KnHUe5eh3uIlkV00k07kCBmd',
        'secret_key_test' => 'sk_test_51QwoVN00pblGEgsXnvqi8qfYpzHtesWWclvK3lzQjPNoHY0dIyOpJmxIkoLqsbmRMEUZpKS5MQ7iFDRlSqVyTo9c006yWetbsd',
        'public_key_live' => 'pk_live_XXXXXX', // Non utilisé en DEV
        'secret_key_live' => 'sk_live_XXXXXX', // Non utilisé en DEV
        'webhook_secret_test' => 'whsec_test_XXXXXXXXXXXX',
        'webhook_secret_live' => 'whsec_live_XXXXXXXXXXXX',
        'api_version' => '2025-08-27.basil',
        'application_fee_percent' => 0,
        'application_fee_minimum' => 0,
        'mode' => 'test', // ← MODE TEST pour le développement
      ],
      // Vous pouvez activer des fonctionnalités de débogage en développement
      'debug' => true,
    ]);
  }

  private function validateApp(): void {
    // Si l'hôte est vide, utiliser une solution de secours (développement par défaut)
    if (empty($this->currentHost)) {
      // Journaliser cette situation anormale
      error_log("WARNING: No host detected, falling back to development environment");
      $this->currentHost = 'dapp.geosector.fr';
    }

    // Si l'hôte n'existe pas dans la configuration, tenter une correction
    if (!isset($this->config[$this->currentHost])) {
      // Gestion des cas spéciaux (anciennes URLs)
      if ($this->currentHost === 'app.geosector.fr') {
        $this->currentHost = 'app3.geosector.fr';
      }

      // Essayer de faire correspondre avec l'un des hôtes connus
      if (!isset($this->config[$this->currentHost])) {
        $knownHosts = array_keys($this->config);
        foreach ($knownHosts as $host) {
          if (strpos($this->currentHost, str_replace(['app3.', 'rapp.', 'dapp.'], '', $host)) !== false) {
            // Correspondance trouvée, utiliser cette configuration
            $this->currentHost = $host;
            break;
          }
        }
      }

      // Si toujours pas de correspondance, utiliser l'environnement de développement par défaut
      if (!isset($this->config[$this->currentHost])) {
        error_log("WARNING: Unknown host '{$this->currentHost}', falling back to development environment");
        $this->currentHost = 'dapp.geosector.fr';
      }
    }

    // Journaliser l'environnement détecté
    $environment = $this->config[$this->currentHost]['env'] ?? 'unknown';
    // error_log("INFO: Environment detected: {$environment} (Host: {$this->currentHost}, IP: {$this->clientIp})");
  }

  /**
   * Retourne le type de client (web, mobile, etc.)
   * 
   * @return string Le type de client ou 'unknown' si non défini
   */
  public function getClientType(): string {
    return $this->headers['X-Client-Type'] ?? $_SERVER['HTTP_X_CLIENT_TYPE'] ?? 'unknown';
  }

  /**
   * Retourne l'identifiant de l'application basé sur l'hôte
   *
   * @return string L'identifiant de l'application (app3.geosector.fr, rapp.geosector.fr, dapp.geosector.fr)
   */
  public function getAppIdentifier(): string {
    return $this->currentHost;
  }

  /**
   * Retourne l'environnement actuel (production, recette, development)
   * 
   * @return string L'environnement actuel
   */
  public function getEnvironment(): string {
    return $this->getCurrentConfig()['env'] ?? 'production';
  }

  /**
   * Vérifie si l'application est en mode développement
   * 
   * @return bool True si l'application est en mode développement
   */
  public function isDevelopment(): bool {
    return $this->getEnvironment() === 'development';
  }

  /**
   * Vérifie si l'application est en mode recette
   * 
   * @return bool True si l'application est en mode recette
   */
  public function isRecette(): bool {
    return $this->getEnvironment() === 'recette';
  }

  /**
   * Vérifie si l'application est en mode production
   * 
   * @return bool True si l'application est en mode production
   */
  public function isProduction(): bool {
    return $this->getEnvironment() === 'production';
  }

  /**
   * Retourne la configuration complète de l'environnement actuel
   * 
   * @return array Configuration de l'environnement
   */
  public function getCurrentConfig(): array {
    return $this->config[$this->currentHost];
  }

  /**
   * Retourne le nom de l'application
   * 
   * @return string Nom de l'application (geosector)
   */
  public function getName(): string {
    return $this->getCurrentConfig()['name'];
  }

  /**
   * Retourne la configuration de la base de données
   *
   * @return array Configuration de la base de données
   */
  public function getDatabaseConfig(): array {
    return $this->getCurrentConfig()['database'];
  }

  /**
   * Retourne la configuration de la base de données des adresses
   *
   * @return array Configuration de la base de données des adresses
   */
  public function getAddressesDatabaseConfig(): array {
    return $this->getCurrentConfig()['addresses_database'];
  }

  /**
   * Retourne la configuration de la base de données des bâtiments
   *
   * @return array Configuration de la base de données des bâtiments
   */
  public function getBuildingsDatabaseConfig(): array {
    return $this->getCurrentConfig()['buildings_database'];
  }

  /**
   * Retourne la clé de chiffrement
   * 
   * @return string Clé de chiffrement
   */
  public function getEncryptionKey(): string {
    return $this->getCurrentConfig()['encryption_key'];
  }

  /**
   * Retourne la configuration SMTP
   * 
   * @return array Configuration SMTP
   */
  public function getSmtpConfig(): array {
    return $this->getCurrentConfig()['smtp'];
  }

  /**
   * Retourne la configuration email
   * 
   * @return array Configuration email
   */
  public function getEmailConfig(): array {
    return $this->getCurrentConfig()['email'];
  }

  /**
   * Retourne la configuration Mapbox
   * 
   * @return array Configuration Mapbox
   */
  public function getMapboxConfig(): array {
    return $this->getCurrentConfig()['mapbox'];
  }

  /**
   * Retourne la configuration Stripe
   * 
   * @return array Configuration Stripe
   */
  public function getStripeConfig(): array {
    return $this->getCurrentConfig()['stripe'];
  }

  /**
   * Retourne la configuration SMS
   * 
   * @return array Configuration SMS
   */
  public function getSmsConfig(): array {
    return $this->getCurrentConfig()['sms'];
  }

  /**
   * Retourne si le mode debug est activé
   * 
   * @return bool True si le mode debug est activé
   */
  public function isDebugEnabled(): bool {
    return $this->getCurrentConfig()['debug'] ?? false;
  }

  /**
   * Retourne la liste des origines autorisées (domaines)
   * 
   * @return array Liste des origines autorisées
   */
  public function getAllowedOrigins(): array {
    return array_keys($this->config);
  }

  /**
   * Vérifie si le client est d'un type spécifique
   * 
   * @param string $type Type de client à vérifier
   * @return bool True si le client est du type spécifié
   */
  public function isClientType(string $type): bool {
    return $this->getClientType() === $type;
  }

  /**
   * Retourne la configuration complète pour l'utilisation externe
   * 
   * @return array Configuration complète
   */
  public function getFullConfig(): array {
    return [
      'environment' => $this->getEnvironment(),
      'database' => $this->getDatabaseConfig(),
      'api' => [
        'allowed_origins' => $this->getAllowedOrigins(),
        'current_site' => $this->getName(),
      ],
      'debug' => $this->isDebugEnabled()
    ];
  }

  /**
   * Retourne l'adresse IP du client
   *
   * @return string L'adresse IP du client
   */
  public function getClientIp(): string {
    return $this->clientIp;
  }

  /**
   * Vérifie si la redirection vers RECETTE est activée
   *
   * @return bool True si la redirection est activée
   */
  public function shouldRedirectToRecette(): bool {
    $value = getenv('REDIRECT_TO_REC');
    return $value === 'true' || $value === '1';
  }

  /**
   * Retourne la configuration des backups
   * 
   * @return array Configuration des backups
   */
  public function getBackupConfig(): array {
    return $this->getCurrentConfig()['backup'];
  }

  /**
   * Retourne la clé de chiffrement des backups
   * 
   * @return string Clé de chiffrement des backups
   */
  public function getBackupEncryptionKey(): string {
    return $this->getCurrentConfig()['backup']['encryption_key'];
  }

  /**
   * Détermine l'adresse IP du client en tenant compte des proxys et load balancers
   * 
   * @return string L'adresse IP du client
   */
  private function getClientIpAddress(): string {
    // Vérifier les en-têtes courants pour l'IP client
    $ipSources = [
      'HTTP_X_REAL_IP',             // Nginx proxy
      'HTTP_CLIENT_IP',             // Proxy partagé
      'HTTP_X_FORWARDED_FOR',       // Proxy ou load balancer courant
      'HTTP_X_FORWARDED',           // Proxy générique
      'HTTP_X_CLUSTER_CLIENT_IP',   // Reverse proxy
      'HTTP_FORWARDED_FOR',         // Proxies précédents
      'HTTP_FORWARDED',             // Format standardisé (RFC 7239)
      'REMOTE_ADDR',                // Fallback direct
    ];

    foreach ($ipSources as $source) {
      if (!empty($_SERVER[$source])) {
        // Pour des en-têtes comme X-Forwarded-For qui peuvent contenir plusieurs IPs séparées par des virgules
        // (format: "client, proxy1, proxy2")
        if ($source === 'HTTP_X_FORWARDED_FOR' || $source === 'HTTP_FORWARDED_FOR') {
          $ips = explode(',', $_SERVER[$source]);
          $clientIp = trim($ips[0]); // Prendre la première adresse (client original)
        } else {
          $clientIp = $_SERVER[$source];
        }

        // Valider l'IP pour éviter les injections
        $filteredIp = filter_var($clientIp, FILTER_VALIDATE_IP);
        if ($filteredIp !== false) {
          return $filteredIp;
        }
      }
    }

    // Si aucune adresse IP valide n'est trouvée, retourner une valeur par défaut
    return '0.0.0.0';
  }
}
