<?php
namespace Core;

/**
 * Classe de configuração centralizada
 * 
 * Versão melhorada do sistema de configuração que:
 * - Utiliza namespaces para organização
 * - Implementa padrão Singleton de forma mais robusta
 * - Melhora o carregamento de variáveis de ambiente
 * - Centraliza configurações do sistema
 */

class Config {
    private static $instance = null;
    private $settings = [];
    private $envLoaded = false;
    
    /**
     * Construtor privado (padrão Singleton)
     */
    private function __construct() {
        // Inicializar configurações padrão
        $this->settings = [
            'debug_mode' => false,
            'log_path' => __DIR__ . '/../../logs',
            'cache_path' => __DIR__ . '/../../cache',
            'uploads_path' => __DIR__ . '/../../uploads',
            'db' => [
                'host' => 'localhost',
                'user' => '',
                'pass' => '',
                'name' => '',
                'charset' => 'utf8mb4'
            ],
            'youtube' => [
                'api_key' => '',
                'channel_id' => '',
                'cache_expiration' => 3600
            ],
            'security' => [
                'csrf_protection' => true,
                'xss_protection' => true,
                'sql_injection_protection' => true
            ]
        ];
        
        // Criar diretórios necessários
        $this->createRequiredDirectories();
    }
    
    /**
     * Previne clonagem do objeto (padrão Singleton)
     */
    private function __clone() {}
    
    /**
     * Previne desserialização do objeto (padrão Singleton)
     */
    private function __wakeup() {}
    
    /**
     * Obtém a instância única da classe
     * 
     * @return Config
     */
    public static function getInstance() {
        if (self::$instance === null) {
            self::$instance = new self();
        }
        
        return self::$instance;
    }
    
    /**
     * Carrega variáveis de ambiente de um arquivo .env
     * 
     * @param string $path Caminho para o arquivo .env
     * @return bool Sucesso ou falha
     */
    public function loadEnv($path = null) {
        if ($this->envLoaded) {
            return true;
        }
        
        if ($path === null) {
            $path = __DIR__ . '/../../.env';
        }
        
        if (!file_exists($path)) {
            $this->createDefaultEnvFile($path);
            return false;
        }
        
        $variables = [];
        $lines = file($path, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
        
        foreach ($lines as $line) {
            // Ignora comentários
            if (strpos(trim($line), '#') === 0) {
                continue;
            }
            
            // Processa linha de variável
            if (strpos($line, '=') !== false) {
                list($name, $value) = explode('=', $line, 2);
                $name = trim($name);
                $value = trim($value);
                
                // Remove aspas se existirem
                if (strpos($value, '"') === 0 && strrpos($value, '"') === strlen($value) - 1) {
                    $value = substr($value, 1, -1);
                } elseif (strpos($value, "'") === 0 && strrpos($value, "'") === strlen($value) - 1) {
                    $value = substr($value, 1, -1);
                }
                
                // Define a variável no array e no ambiente
                $variables[$name] = $value;
                putenv("{$name}={$value}");
                
                // Também define como variável global para fácil acesso
                if (!isset($_ENV[$name])) {
                    $_ENV[$name] = $value;
                }
                
                if (!isset($_SERVER[$name])) {
                    $_SERVER[$name] = $value;
                }
                
                // Atualiza configurações com base nas variáveis de ambiente
                $this->updateSettingsFromEnv($name, $value);
            }
        }
        
        $this->envLoaded = true;
        return true;
    }
    
    /**
     * Atualiza configurações com base nas variáveis de ambiente
     * 
     * @param string $name Nome da variável
     * @param string $value Valor da variável
     */
    private function updateSettingsFromEnv($name, $value) {
        switch ($name) {
            case 'DEBUG_MODE':
                $this->settings['debug_mode'] = filter_var($value, FILTER_VALIDATE_BOOLEAN);
                break;
            case 'DB_HOST':
                $this->settings['db']['host'] = $value;
                break;
            case 'DB_USER':
                $this->settings['db']['user'] = $value;
                break;
            case 'DB_PASS':
                $this->settings['db']['pass'] = $value;
                break;
            case 'DB_NAME':
                $this->settings['db']['name'] = $value;
                break;
            case 'DB_CHARSET':
                $this->settings['db']['charset'] = $value;
                break;
            case 'YOUTUBE_API_KEY':
                $this->settings['youtube']['api_key'] = $value;
                break;
            case 'YOUTUBE_CHANNEL_ID':
                $this->settings['youtube']['channel_id'] = $value;
                break;
            case 'YOUTUBE_CACHE_EXPIRATION':
                $this->settings['youtube']['cache_expiration'] = intval($value);
                break;
            case 'LOG_PATH':
                $this->settings['log_path'] = $value;
                break;
            case 'CACHE_PATH':
                $this->settings['cache_path'] = $value;
                break;
            case 'UPLOADS_PATH':
                $this->settings['uploads_path'] = $value;
                break;
        }
    }
    
    /**
     * Cria um arquivo .env padrão
     * 
     * @param string $path Caminho para o arquivo .env
     */
    private function createDefaultEnvFile($path) {
        $content = "# Arquivo de configuração de ambiente\n";
        $content .= "# Gerado automaticamente em " . date('Y-m-d H:i:s') . "\n\n";
        $content .= "# Modo de depuração (true/false)\n";
        $content .= "DEBUG_MODE=false\n\n";
        $content .= "# Configurações do banco de dados\n";
        $content .= "DB_HOST=localhost\n";
        $content .= "DB_USER=\n";
        $content .= "DB_PASS=\n";
        $content .= "DB_NAME=\n";
        $content .= "DB_CHARSET=utf8mb4\n\n";
        $content .= "# Configurações do YouTube\n";
        $content .= "YOUTUBE_API_KEY=\n";
        $content .= "YOUTUBE_CHANNEL_ID=\n";
        $content .= "YOUTUBE_CACHE_EXPIRATION=3600\n\n";
        $content .= "# Caminhos de diretórios\n";
        $content .= "LOG_PATH=" . __DIR__ . "/../../logs\n";
        $content .= "CACHE_PATH=" . __DIR__ . "/../../cache\n";
        $content .= "UPLOADS_PATH=" . __DIR__ . "/../../uploads\n";
        
        file_put_contents($path, $content);
    }
    
    /**
     * Cria diretórios necessários para o sistema
     */
    private function createRequiredDirectories() {
        $directories = [
            $this->settings['log_path'],
            $this->settings['cache_path'],
            $this->settings['uploads_path']
        ];
        
        foreach ($directories as $dir) {
            if (!is_dir($dir)) {
                mkdir($dir, 0755, true);
            }
        }
    }
    
    /**
     * Obtém uma configuração específica
     * 
     * @param string $key Chave da configuração (suporta notação de ponto, ex: 'db.host')
     * @param mixed $default Valor padrão se a configuração não existir
     * @return mixed Valor da configuração ou valor padrão
     */
    public function get($key, $default = null) {
        // Verificar se é uma chave com notação de ponto (ex: 'db.host')
        if (strpos($key, '.') !== false) {
            $parts = explode('.', $key);
            $config = $this->settings;
            
            foreach ($parts as $part) {
                if (!isset($config[$part])) {
                    return $default;
                }
                $config = $config[$part];
            }
            
            return $config;
        }
        
        return isset($this->settings[$key]) ? $this->settings[$key] : $default;
    }
    
    /**
     * Define uma configuração específica
     * 
     * @param string $key Chave da configuração (suporta notação de ponto, ex: 'db.host')
     * @param mixed $value Valor da configuração
     * @return Config Instância atual para encadeamento
     */
    public function set($key, $value) {
        // Verificar se é uma chave com notação de ponto (ex: 'db.host')
        if (strpos($key, '.') !== false) {
            $parts = explode('.', $key);
            $config = &$this->settings;
            
            foreach ($parts as $i => $part) {
                if ($i === count($parts) - 1) {
                    $config[$part] = $value;
                } else {
                    if (!isset($config[$part]) || !is_array($config[$part])) {
                        $config[$part] = [];
                    }
                    $config = &$config[$part];
                }
            }
        } else {
            $this->settings[$key] = $value;
        }
        
        return $this;
    }
    
    /**
     * Verifica se uma configuração existe
     * 
     * @param string $key Chave da configuração (suporta notação de ponto, ex: 'db.host')
     * @return bool True se a configuração existir, false caso contrário
     */
    public function has($key) {
        // Verificar se é uma chave com notação de ponto (ex: 'db.host')
        if (strpos($key, '.') !== false) {
            $parts = explode('.', $key);
            $config = $this->settings;
            
            foreach ($parts as $part) {
                if (!isset($config[$part])) {
                    return false;
                }
                $config = $config[$part];
            }
            
            return true;
        }
        
        return isset($this->settings[$key]);
    }
    
    /**
     * Obtém todas as configurações
     * 
     * @return array Array com todas as configurações
     */
    public function all() {
        return $this->settings;
    }
}
