<?php
/**
 * Security Functions
 * IP blocking, session management, password policies
 */

/**
 * Whether failed-login IP lockout is active (settings: login_ip_lockout_enabled).
 */
function isLoginIpLockoutEnabled(): bool
{
    require_once __DIR__ . '/settings.php';
    return getSetting('login_ip_lockout_enabled', '0') === '1';
}

/**
 * Check if an IP address is blocked
 */
function isIpBlocked($ip_address = null) {
    global $pdo;

    if (!isLoginIpLockoutEnabled()) {
        return false;
    }
    
    if ($ip_address === null) {
        $ip_address = $_SERVER['REMOTE_ADDR'] ?? null;
    }
    
    if (!$ip_address || !isset($pdo)) {
        return false;
    }
    
    try {
        // Check if activity_logs table exists
        $pdo->query('SELECT 1 FROM activity_logs LIMIT 1');
    } catch (PDOException $e) {
        return false;
    }
    
    // Get security settings
    require_once __DIR__ . '/settings.php';
    $maxAttempts = (int)getSetting('max_login_attempts', '5');
    $lockoutDuration = (int)getSetting('lockout_duration_minutes', '15');
    
    // Check failed login attempts in the last lockout duration
    $stmt = $pdo->prepare("
        SELECT COUNT(*) as attempts
        FROM activity_logs
        WHERE action = 'login_failed'
          AND ip_address = ?
          AND created_at >= DATE_SUB(NOW(), INTERVAL ? MINUTE)
    ");
    $stmt->execute([$ip_address, $lockoutDuration]);
    $result = $stmt->fetch();
    
    return ($result && (int)$result['attempts'] >= $maxAttempts);
}

/**
 * Get failed login attempts count for an IP
 */
function getFailedLoginAttempts($ip_address = null) {
    global $pdo;
    
    if ($ip_address === null) {
        $ip_address = $_SERVER['REMOTE_ADDR'] ?? null;
    }
    
    if (!$ip_address || !isset($pdo)) {
        return 0;
    }
    
    try {
        $pdo->query('SELECT 1 FROM activity_logs LIMIT 1');
    } catch (PDOException $e) {
        return 0;
    }
    
    require_once __DIR__ . '/settings.php';
    $lockoutDuration = (int)getSetting('lockout_duration_minutes', '15');
    
    $stmt = $pdo->prepare("
        SELECT COUNT(*) as attempts
        FROM activity_logs
        WHERE action = 'login_failed'
          AND ip_address = ?
          AND created_at >= DATE_SUB(NOW(), INTERVAL ? MINUTE)
    ");
    $stmt->execute([$ip_address, $lockoutDuration]);
    $result = $stmt->fetch();
    
    return (int)($result['attempts'] ?? 0);
}

/**
 * Check if IP is in whitelist
 */
function isIpWhitelisted($ip_address = null) {
    global $pdo;
    
    if ($ip_address === null) {
        $ip_address = $_SERVER['REMOTE_ADDR'] ?? null;
    }
    
    if (!$ip_address || !isset($pdo)) {
        return false;
    }
    
    try {
        require_once __DIR__ . '/settings.php';
        $whitelist = getSetting('ip_whitelist', '');
        if (empty($whitelist)) {
            return false;
        }
        
        $ips = array_map('trim', explode(',', $whitelist));
        return in_array($ip_address, $ips);
    } catch (Exception $e) {
        return false;
    }
}

/**
 * Check if IP is in blacklist
 */
function isIpBlacklisted($ip_address = null) {
    global $pdo;
    
    if ($ip_address === null) {
        $ip_address = $_SERVER['REMOTE_ADDR'] ?? null;
    }
    
    if (!$ip_address || !isset($pdo)) {
        return false;
    }
    
    try {
        require_once __DIR__ . '/settings.php';
        $blacklist = getSetting('ip_blacklist', '');
        if (empty($blacklist)) {
            return false;
        }
        
        $ips = array_map('trim', explode(',', $blacklist));
        return in_array($ip_address, $ips);
    } catch (Exception $e) {
        return false;
    }
}

/**
 * Validate password against policy
 */
function validatePassword($password) {
    require_once __DIR__ . '/settings.php';
    
    $minLength = (int)getSetting('min_password_length', '6');
    $requireUppercase = getSetting('password_require_uppercase', '0') === '1';
    $requireLowercase = getSetting('password_require_lowercase', '0') === '1';
    $requireNumbers = getSetting('password_require_numbers', '0') === '1';
    $requireSpecial = getSetting('password_require_special', '0') === '1';
    
    $errors = [];
    
    if (strlen($password) < $minLength) {
        $errors[] = "Password must be at least {$minLength} characters long.";
    }
    
    if ($requireUppercase && !preg_match('/[A-Z]/', $password)) {
        $errors[] = "Password must contain at least one uppercase letter.";
    }
    
    if ($requireLowercase && !preg_match('/[a-z]/', $password)) {
        $errors[] = "Password must contain at least one lowercase letter.";
    }
    
    if ($requireNumbers && !preg_match('/[0-9]/', $password)) {
        $errors[] = "Password must contain at least one number.";
    }
    
    if ($requireSpecial && !preg_match('/[^A-Za-z0-9]/', $password)) {
        $errors[] = "Password must contain at least one special character.";
    }
    
    return [
        'valid' => empty($errors),
        'errors' => $errors
    ];
}

/**
 * Get session timeout in seconds
 */
function getSessionTimeout() {
    require_once __DIR__ . '/settings.php';
    $timeoutMinutes = (int)getSetting('session_timeout_minutes', '60');
    return $timeoutMinutes * 60;
}

/**
 * Check if session has expired
 */
function isSessionExpired() {
    if (empty($_SESSION['last_activity'])) {
        return false;
    }
    
    $timeout = getSessionTimeout();
    return (time() - $_SESSION['last_activity']) > $timeout;
}

/**
 * Update session activity timestamp
 */
function updateSessionActivity() {
    $_SESSION['last_activity'] = time();
}

/**
 * Get remaining session time in seconds
 */
function getRemainingSessionTime() {
    if (empty($_SESSION['last_activity'])) {
        return getSessionTimeout();
    }
    
    $timeout = getSessionTimeout();
    $elapsed = time() - $_SESSION['last_activity'];
    return max(0, $timeout - $elapsed);
}

/**
 * Verify the logged-in user's password (destructive-action confirmation).
 * Does not depend on includes/auth.php to avoid circular requires.
 *
 * @param PDO $pdo
 */
function nazareth_verify_current_user_password($pdo, $password) {
    if (!isset($pdo) || $password === null || $password === '') {
        return false;
    }
    $uid = $_SESSION['user_id'] ?? null;
    if (!$uid) {
        return false;
    }
    try {
        $stmt = $pdo->prepare('SELECT password FROM users WHERE id = ? AND active = 1');
        $stmt->execute([(int) $uid]);
        $hash = $stmt->fetchColumn();
        if (!$hash || !is_string($hash)) {
            return false;
        }

        return password_verify((string) $password, $hash);
    } catch (PDOException $e) {
        return false;
    }
}
