<?php
/**
 * RoVo Real Estate Platform
 * Secure Configuration File
 * PHP 8.2+ Compatible
 */

// Prevent direct access
if (!defined('ROVO_APP')) {
    define('ROVO_APP', true);
}

// Error Reporting (Set to 0 in production)
error_reporting(E_ALL);
ini_set('display_errors', 0);
ini_set('log_errors', 1);
ini_set('error_log', __DIR__ . '/logs/php_errors.log');

// Session Configuration
ini_set('session.cookie_httponly', 1);
ini_set('session.use_only_cookies', 1);
ini_set('session.cookie_secure', 1);
ini_set('session.cookie_samesite', 'Strict');
ini_set('session.gc_maxlifetime', 3600);

// Database Configuration
define('DB_HOST', 'localhost');
define('DB_USER', 'root');
define('DB_PASS', '');
define('DB_NAME', 'rovo_estate');
define('DB_CHARSET', 'utf8mb4');

// Application Configuration
define('APP_NAME', 'RoVo Nigeria');
define('APP_URL', 'http://localhost/rovo');
define('APP_ENV', 'development'); // production, development
define('APP_DEBUG', true);

// Path Configuration
define('BASE_PATH', __DIR__);
define('UPLOAD_PATH', BASE_PATH . '/uploads');
define('ADMIN_PATH', BASE_PATH . '/admin');

// URL Configuration
define('BASE_URL', APP_URL);
define('ASSETS_URL', BASE_URL . '/assets');
define('UPLOADS_URL', BASE_URL . '/uploads');

// Upload Directories
define('PROPERTY_UPLOAD_DIR', UPLOAD_PATH . '/properties');
define('LAND_UPLOAD_DIR', UPLOAD_PATH . '/lands');
define('DOCUMENT_UPLOAD_DIR', UPLOAD_PATH . '/documents');
define('PROFILE_UPLOAD_DIR', UPLOAD_PATH . '/profiles');
define('MATERIAL_UPLOAD_DIR', UPLOAD_PATH . '/materials');
define('BLOG_UPLOAD_DIR', UPLOAD_PATH . '/blog');

// Security Configuration
define('ENCRYPTION_KEY', 'your-32-character-encryption-key'); // Change this!
define('CSRF_TOKEN_NAME', 'csrf_token');
define('PASSWORD_SALT', 'your-password-salt-here'); // Change this!
define('MAX_LOGIN_ATTEMPTS', 5);
define('LOCKOUT_TIME', 900); // 15 minutes

// Payment Gateway Configuration
define('PAYSTACK_PUBLIC_KEY', 'pk_test_xxxxxxxxxxxx');
define('PAYSTACK_SECRET_KEY', 'sk_test_xxxxxxxxxxxx');
define('FLUTTERWAVE_PUBLIC_KEY', 'FLWPUBK_TEST-xxxxxxxxxxxx');
define('FLUTTERWAVE_SECRET_KEY', 'FLWSECK_TEST-xxxxxxxxxxxx');

// Application Settings
define('COMMISSION_RATE', 15); // Percentage
define('VERIFICATION_FEE', 3000); // Naira
define('ITEMS_PER_PAGE', 10);
define('MAX_FILE_SIZE', 5242880); // 5MB in bytes
define('ALLOWED_IMAGE_TYPES', ['image/jpeg', 'image/png', 'image/jpg']);
define('ALLOWED_DOCUMENT_TYPES', ['application/pdf', 'image/jpeg', 'image/png']);

// Email Configuration
define('SMTP_HOST', 'smtp.gmail.com');
define('SMTP_PORT', 587);
define('SMTP_USERNAME', 'your-email@gmail.com');
define('SMTP_PASSWORD', 'your-app-password');
define('SMTP_FROM_EMAIL', 'noreply@rovo.com');
define('SMTP_FROM_NAME', 'RoVo Nigeria');

// SMS Configuration (Termii)
define('SMS_API_KEY', 'your-termii-api-key');
define('SMS_SENDER_ID', 'RoVo');

// WhatsApp Configuration
define('WHATSAPP_NUMBER', '2349065136669');
define('WHATSAPP_API_TOKEN', 'your-whatsapp-api-token');

// Timezone
date_default_timezone_set('Africa/Lagos');

// Create necessary directories if they don't exist
$directories = [
    UPLOAD_PATH,
    PROPERTY_UPLOAD_DIR,
    LAND_UPLOAD_DIR,
    DOCUMENT_UPLOAD_DIR,
    PROFILE_UPLOAD_DIR,
    MATERIAL_UPLOAD_DIR,
    BLOG_UPLOAD_DIR,
    BASE_PATH . '/logs'
];

foreach ($directories as $dir) {
    if (!is_dir($dir)) {
        mkdir($dir, 0755, true);
    }
}

// Create .htaccess for upload directories
$htaccess_content = "Options -Indexes\nDeny from all\n<FilesMatch '\.(jpg|jpeg|png|pdf)$'>\n    Allow from all\n</FilesMatch>";
foreach ([PROPERTY_UPLOAD_DIR, LAND_UPLOAD_DIR, DOCUMENT_UPLOAD_DIR, PROFILE_UPLOAD_DIR, MATERIAL_UPLOAD_DIR] as $dir) {
    $htaccess_file = $dir . '/.htaccess';
    if (!file_exists($htaccess_file)) {
        file_put_contents($htaccess_file, $htaccess_content);
    }
}

// Database Connection Class
class Database {
    private static $instance = null;
    private $conn;
    
    private function __construct() {
        try {
            $dsn = "mysql:host=" . DB_HOST . ";dbname=" . DB_NAME . ";charset=" . DB_CHARSET;
            $options = [
                PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
                PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
                PDO::ATTR_EMULATE_PREPARES => false,
                PDO::ATTR_PERSISTENT => false
            ];
            
            $this->conn = new PDO($dsn, DB_USER, DB_PASS, $options);
        } catch(PDOException $e) {
            if (APP_DEBUG) {
                die("Connection failed: " . $e->getMessage());
            } else {
                die("Database connection error. Please try again later.");
            }
        }
    }
    
    public static function getInstance() {
        if (self::$instance === null) {
            self::$instance = new self();
        }
        return self::$instance;
    }
    
    public function getConnection() {
        return $this->conn;
    }
    
    public function query($sql, $params = []) {
        try {
            $stmt = $this->conn->prepare($sql);
            $stmt->execute($params);
            return $stmt;
        } catch(PDOException $e) {
            $this->logError($e->getMessage(), $sql, $params);
            throw $e;
        }
    }
    
    public function fetchAll($sql, $params = []) {
        $stmt = $this->query($sql, $params);
        return $stmt->fetchAll();
    }
    
    public function fetchOne($sql, $params = []) {
        $stmt = $this->query($sql, $params);
        return $stmt->fetch();
    }
    
    public function execute($sql, $params = []) {
        $stmt = $this->query($sql, $params);
        return $stmt->rowCount();
    }
    
    public function lastInsertId() {
        return $this->conn->lastInsertId();
    }
    
    public function beginTransaction() {
        return $this->conn->beginTransaction();
    }
    
    public function commit() {
        return $this->conn->commit();
    }
    
    public function rollBack() {
        return $this->conn->rollBack();
    }
    
    private function logError($error, $sql, $params) {
        $log = date('Y-m-d H:i:s') . " - ERROR: $error\n";
        $log .= "SQL: $sql\n";
        $log .= "Params: " . json_encode($params) . "\n\n";
        file_put_contents(BASE_PATH . '/logs/db_errors.log', $log, FILE_APPEND);
    }
    
    // Prevent cloning
    private function __clone() {}
    
    // Prevent unserialization
    public function __wakeup() {
        throw new Exception("Cannot unserialize singleton");
    }
}

// Security Helper Functions
class Security {
    
    public static function generateToken($length = 32) {
        return bin2hex(random_bytes($length));
    }
    
    public static function generateCSRFToken() {
        if (empty($_SESSION[CSRF_TOKEN_NAME])) {
            $_SESSION[CSRF_TOKEN_NAME] = self::generateToken();
        }
        return $_SESSION[CSRF_TOKEN_NAME];
    }
    
    public static function validateCSRFToken($token) {
        if (empty($_SESSION[CSRF_TOKEN_NAME]) || empty($token)) {
            return false;
        }
        return hash_equals($_SESSION[CSRF_TOKEN_NAME], $token);
    }
    
    public static function sanitizeInput($data) {
        if (is_array($data)) {
            foreach ($data as $key => $value) {
                $data[$key] = self::sanitizeInput($value);
            }
        } else {
            $data = trim($data);
            $data = stripslashes($data);
            $data = htmlspecialchars($data, ENT_QUOTES, 'UTF-8');
        }
        return $data;
    }
    
    public static function hashPassword($password) {
        return password_hash($password, PASSWORD_ARGON2ID, [
            'memory_cost' => 2048,
            'time_cost' => 4,
            'threads' => 3
        ]);
    }
    
    public static function verifyPassword($password, $hash) {
        return password_verify($password, $hash);
    }
    
    public static function encrypt($data) {
        $iv = random_bytes(16);
        $encrypted = openssl_encrypt($data, 'AES-256-CBC', ENCRYPTION_KEY, 0, $iv);
        return base64_encode($encrypted . '::' . $iv);
    }
    
    public static function decrypt($data) {
        list($encrypted_data, $iv) = explode('::', base64_decode($data), 2);
        return openssl_decrypt($encrypted_data, 'AES-256-CBC', ENCRYPTION_KEY, 0, $iv);
    }
    
    public static function validateEmail($email) {
        return filter_var($email, FILTER_VALIDATE_EMAIL) !== false;
    }
    
    public static function validatePhone($phone) {
        // Nigerian phone number validation
        $pattern = '/^(\+?234|0)[789]\d{9}$/';
        return preg_match($pattern, $phone);
    }
    
    public static function sanitizeFilename($filename) {
        $filename = preg_replace('/[^a-zA-Z0-9._-]/', '', $filename);
        return substr($filename, 0, 255);
    }
    
    public static function generateSlug($text) {
        $text = strtolower($text);
        $text = preg_replace('/[^a-z0-9-]/', '-', $text);
        $text = preg_replace('/-+/', '-', $text);
        return trim($text, '-');
    }
    
    public static function getClientIP() {
        if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
            return $_SERVER['HTTP_CLIENT_IP'];
        } elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
            return $_SERVER['HTTP_X_FORWARDED_FOR'];
        } else {
            return $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0';
        }
    }
    
    public static function checkLoginAttempts($user_id) {
        $db = Database::getInstance();
        $sql = "SELECT login_attempts, locked_until FROM users WHERE id = ?";
        $user = $db->fetchOne($sql, [$user_id]);
        
        if ($user && $user['locked_until']) {
            if (strtotime($user['locked_until']) > time()) {
                return false;
            }
        }
        return true;
    }
    
    public static function recordLoginAttempt($user_id, $success = false) {
        $db = Database::getInstance();
        
        if ($success) {
            $sql = "UPDATE users SET login_attempts = 0, locked_until = NULL, last_login = NOW() WHERE id = ?";
            $db->execute($sql, [$user_id]);
        } else {
            $sql = "UPDATE users SET login_attempts = login_attempts + 1 WHERE id = ?";
            $db->execute($sql, [$user_id]);
            
            $user = $db->fetchOne("SELECT login_attempts FROM users WHERE id = ?", [$user_id]);
            if ($user && $user['login_attempts'] >= MAX_LOGIN_ATTEMPTS) {
                $locked_until = date('Y-m-d H:i:s', time() + LOCKOUT_TIME);
                $sql = "UPDATE users SET locked_until = ? WHERE id = ?";
                $db->execute($sql, [$locked_until, $user_id]);
            }
        }
    }
}

// Start session if not already started
if (session_status() === PHP_SESSION_NONE) {
    session_start();
}

// Security headers
header("X-Content-Type-Options: nosniff");
header("X-Frame-Options: DENY");
header("X-XSS-Protection: 1; mode=block");
header("Referrer-Policy: strict-origin-when-cross-origin");
header("Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://cdn.jsdelivr.net https://cdnjs.cloudflare.com; style-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net https://cdnjs.cloudflare.com https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com https://cdnjs.cloudflare.com; img-src 'self' data: https:; connect-src 'self' https://api.paystack.co https://api.flutterwave.com;");

// Initialize database connection
//$db = Database::getInstance()->getConnection();
$db = Database::getInstance();
