<?php
// src/helpers.php

// Función para iniciar sesión segura
function secure_session_start() {
    ini_set('session.use_only_cookies', 1);
    ini_set('session.cookie_httponly', 1);
    ini_set('session.cookie_secure', isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on');
    ini_set('session.cookie_samesite', 'Strict');
    ini_set('session.use_strict_mode', 1);
    
    session_start();
    
    // Regenerar ID de sesión periódicamente
    if (!isset($_SESSION['last_regeneration'])) {
        session_regenerate_id(true);
        $_SESSION['last_regeneration'] = time();
    } elseif (time() - $_SESSION['last_regeneration'] > 1800) { // 30 minutos
        session_regenerate_id(true);
        $_SESSION['last_regeneration'] = time();
    }
}

// Función para cargar vistas
function view($name, $data = []) {
  extract($data);
  include __DIR__ . "/views/_header.php";
  include __DIR__ . "/views/$name.php";
  include __DIR__ . "/views/_footer.php";
}

// Función para redireccionar
function redirect($path, $params = []) {
    if ($path === '/') {
        $url = './';
    } else {
        $url = './?r=' . urlencode($path);
        
        // Agregar parámetros adicionales
        if (!empty($params)) {
            foreach ($params as $key => $value) {
                $url .= '&' . urlencode($key) . '=' . urlencode($value);
            }
        }
    }
    header("Location: $url");
    exit;
}

// Función para mensajes flash
function flash($key, $msg = null) {
  if ($msg === null) {
    if (!empty($_SESSION['flash'][$key])) {
      $m = $_SESSION['flash'][$key];
      unset($_SESSION['flash'][$key]);
      return $m;
    }
    return null;
  } else {
    $_SESSION['flash'][$key] = $msg;
  }
}

// Requerir login
function require_login() {
  if (empty($_SESSION['user'])) {
    flash('error', 'Debes iniciar sesión.');
    redirect('login');
  }
}

// Requerir verificación de email
function require_email_verified() {
  require_login();
  
  if (empty($_SESSION['user']['email_verified'])) {
    flash('error', 'Debes verificar tu email para acceder a esta función.');
    redirect('profile');
  }
}

// Requerir rol específico (para administración)
function require_role($role) {
  require_login();
  
  if (empty($_SESSION['user']['role']) || $_SESSION['user']['role'] !== $role) {
    flash('error', 'No tienes permisos para acceder a esta área.');
    redirect('dashboard');
  }
}

// Escapar HTML
function h($v){ 
    return htmlspecialchars((string)$v, ENT_QUOTES, 'UTF-8'); 
}

// Validar CSRF
function validate_csrf() {
  if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    if (!isset($_POST['csrf']) || $_POST['csrf'] !== $_SESSION['csrf']) {
      flash('error', 'Token de seguridad inválido.');
      redirect($_SERVER['HTTP_REFERER'] ?? 'dashboard');
    }
  }
}

// Generar campo CSRF
function csrf_field() {
  return '<input type="hidden" name="csrf" value="' . h($_SESSION['csrf']) . '">';
}

// Generar ID de conversación
function generate_conversation_id($user1_id, $user2_id) {
  return $user1_id < $user2_id ? "$user1_id-$user2_id" : "$user2_id-$user1_id";
}

// Sanitizar datos de entrada
function sanitize_input($data) {
    if (is_array($data)) {
        return array_map('sanitize_input', $data);
    }
    return htmlspecialchars(trim($data), ENT_QUOTES, 'UTF-8');
}

// Validar email
function validate_email($email) {
    return filter_var($email, FILTER_VALIDATE_EMAIL);
}

// Validar URL
function validate_url($url) {
    return filter_var($url, FILTER_VALIDATE_URL);
}

// Limitar texto
function limit_text($text, $limit = 100) {
    if (strlen($text) <= $limit) {
        return $text;
    }
    return substr($text, 0, $limit) . '...';
}

// Formato de fecha amigable
function friendly_date($date) {
    $now = new DateTime();
    $date = new DateTime($date);
    $diff = $now->diff($date);
    
    if ($diff->y > 0) return $diff->y . ' año' . ($diff->y > 1 ? 's' : '') . ' atrás';
    if ($diff->m > 0) return $diff->m . ' mes' . ($diff->m > 1 ? 'es' : '') . ' atrás';
    if ($diff->d > 0) return $diff->d . ' día' . ($diff->d > 1 ? 's' : '') . ' atrás';
    if ($diff->h > 0) return $diff->h . ' hora' . ($diff->h > 1 ? 's' : '') . ' atrás';
    if ($diff->i > 0) return $diff->i . ' minuto' . ($diff->i > 1 ? 's' : '') . ' atrás';
    return 'Hace un momento';
}

// Función para mostrar tiempo transcurrido
function time_elapsed_string($datetime, $full = false) {
    $now = new DateTime;
    $ago = new DateTime($datetime);
    $diff = $now->diff($ago);

    $diff->w = floor($diff->d / 7);
    $diff->d -= $diff->w * 7;

    $string = array(
        'y' => 'año',
        'm' => 'mes',
        'w' => 'semana',
        'd' => 'día',
        'h' => 'hora',
        'i' => 'minuto',
        's' => 'segundo',
    );
    
    foreach ($string as $k => &$v) {
        if ($diff->$k) {
            $v = $diff->$k . ' ' . $v . ($diff->$k > 1 ? 's' : '');
        } else {
            unset($string[$k]);
        }
    }

    if (!$full) $string = array_slice($string, 0, 1);
    return $string ? implode(', ', $string) . ' atrás' : 'justo ahora';
}

// Verificar si es móvil
function is_mobile() {
    return preg_match("/(android|webos|iphone|ipad|ipod|blackberry|windows phone)/i", $_SERVER['HTTP_USER_AGENT']);
}

// Obtener la URL base
function base_url($path = '') {
    global $CONFIG;
    $base = rtrim($CONFIG['app_url'], '/');
    return $base . '/' . ltrim($path, '/');
}

// Debug function
function dd($data) {
    echo '<pre>';
    print_r($data);
    echo '</pre>';
    die();
}

// === Funciones de seguridad mejoradas ===

/**
 * Verificar edad (mayor de 16 años)
 */
function is_over_16($birth_date) {
    $birthday = new DateTime($birth_date);
    $today = new DateTime();
    $age = $today->diff($birthday)->y;
    return $age >= 16;
}

/**
 * Generar token seguro
 */
function generate_secure_token($length = 64) {
    return bin2hex(random_bytes($length / 2));
}

/**
 * Formatear tiempo de bloqueo para mostrar al usuario
 */
function format_lock_time($lock_time) {
    $now = new DateTime();
    $lock = new DateTime($lock_time);
    $diff = $now->diff($lock);
    
    if ($diff->h > 0) {
        return $diff->h . ' hora(s) y ' . $diff->i . ' minuto(s)';
    } else {
        return $diff->i . ' minuto(s)';
    }
}

/**
 * Obtener la IP del cliente
 */
function get_client_ip() {
    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'] ?? 'unknown';
    }
}

/**
 * Validar fuerza de contraseña
 */
function validate_password_strength($password) {
    if (strlen($password) < 8) {
        return 'La contraseña debe tener al menos 8 caracteres';
    }
    
    if (!preg_match('/[A-Z]/', $password)) {
        return 'La contraseña debe contener al menos una letra mayúscula';
    }
    
    if (!preg_match('/[a-z]/', $password)) {
        return 'La contraseña debe contener al menos una letra minúscula';
    }
    
    if (!preg_match('/[0-9]/', $password)) {
        return 'La contraseña debe contener al menos un número';
    }
    
    return true;
}

// === Timezone helpers ===
// App timezone: override by setting $_SESSION['timezone'] = 'Europe/Berlin' (or your choice)
if (!function_exists('app_timezone')) {
    function app_timezone(): string {
        return $_SESSION['timezone'] ?? 'Europe/Madrid';
    }
}

if (!function_exists('fdt')) {
    /**
     * Format datetime stored as UTC to local app timezone.
     * @param mixed $when String "Y-m-d H:i:s" or UNIX timestamp
     * @param string $fmt PHP date format
     * @return string
     */
    function fdt($when, string $fmt = 'd/m/Y H:i'): string {
        try {
            $src = new DateTimeZone('UTC'); // stored as UTC
            $dst = new DateTimeZone(app_timezone());
            if (is_numeric($when)) {
                $dt = (new DateTime('@'.$when))->setTimezone($src);
            } else {
                $dt = new DateTime((string)$when, $src);
            }
            $dt->setTimezone($dst);
            return $dt->format($fmt);
        } catch (Throwable $e) {
            // Fallback without timezone conversion
            return date($fmt, is_numeric($when) ? (int)$when : strtotime((string)$when));
        }
    }
}

// === FUNCIONES DE ANUNCIOS MEJORADAS - VERSIÓN CORREGIDA ===

/**
 * Actualizar estados automáticamente de anuncios (CORREGIDO - VERSIÓN SEGURA)
 */
function updateAdStatusAutomatically($db) {
    // Verificar que la conexión a BD esté disponible
    if (!$db || !($db instanceof PDO)) {
        error_log("❌ Error: Conexión a BD no disponible en updateAdStatusAutomatically");
        return false;
    }
    
    try {
        error_log("🔄 Iniciando actualización automática de estados de anuncios...");
        
        // 1. Activar anuncios programados que deben empezar
        $active_stmt = $db->prepare("UPDATE ads SET status = 'active' WHERE status = 'pending' AND start_date <= NOW() AND end_date > NOW()");
        $active_result = $active_stmt->execute();
        $active_count = $active_stmt->rowCount();
        
        // 2. Pausar anuncios activos que han expirado
        $pause_stmt = $db->prepare("UPDATE ads SET status = 'paused' WHERE status = 'active' AND end_date < NOW()");
        $pause_result = $pause_stmt->execute();
        $pause_count = $pause_stmt->rowCount();
        
        // 3. Marcar como expirados los anuncios que ya pasaron su fecha final
        $expired_stmt = $db->prepare("UPDATE ads SET status = 'expired' WHERE status IN ('active', 'paused') AND end_date < DATE_SUB(NOW(), INTERVAL 1 DAY)");
        $expired_result = $expired_stmt->execute();
        $expired_count = $expired_stmt->rowCount();
        
        error_log("✅ Estados actualizados: " . 
                 $active_count . " activados, " . 
                 $pause_count . " pausados, " . 
                 $expired_count . " expirados");
        
        return true;
    } catch (Exception $e) {
        error_log("❌ Error actualizando estados de anuncios: " . $e->getMessage());
        return false;
    }
}

/**
 * Obtener anuncios activos para dashboard (CORREGIDO - VERSIÓN SEGURA)
 */
function getActiveAdsForDashboard($db, $limit = 3) {
    // Verificar que la conexión a BD esté disponible
    if (!$db || !($db instanceof PDO)) {
        error_log("❌ Error: Conexión a BD no disponible en getActiveAdsForDashboard");
        return [];
    }
    
    try {
        // Primero actualizar estados automáticamente
        updateAdStatusAutomatically($db);
        
        // Obtener anuncios activos que están en su período válido
        $stmt = $db->prepare("
            SELECT * FROM ads 
            WHERE status = 'active' 
            AND start_date <= NOW() 
            AND end_date > NOW()
            AND (max_impressions IS NULL OR impressions < max_impressions)
            ORDER BY created_at DESC 
            LIMIT ?
        ");
        $stmt->execute([$limit]);
        $ads = $stmt->fetchAll();
        
        return $ads;
    } catch (Exception $e) {
        error_log("❌ Error obteniendo anuncios activos: " . $e->getMessage());
        return [];
    }
}

/**
 * Registrar impresión de anuncio (MEJORADA)
 */
function trackAdImpression($db, $ad_id) {
    try {
        // Verificar que la conexión a BD esté disponible
        if (!$db || !($db instanceof PDO)) {
            error_log("❌ Error: Conexión a BD no disponible en trackAdImpression");
            return false;
        }

        if (session_status() === PHP_SESSION_NONE) {
            session_start();
        }

        // De-duplicar impresiones: 1 por usuario/sesión cada 10 segundos por anuncio
        $key = 'ad_imp_' . $ad_id;
        $now = time();
        if (isset($_SESSION[$key]) && ($now - (int)$_SESSION[$key]) < 10) {
            return false;
        }
        $_SESSION[$key] = $now;

        // Verificar que el anuncio existe y está activo en su ventana temporal
        $check_stmt = $db->prepare("
            SELECT id FROM ads 
            WHERE id = ? AND status = 'active' 
            AND start_date <= NOW() AND end_date > NOW()
        ");
        $check_stmt->execute([$ad_id]);
        if (!$check_stmt->fetch()) {
            return false;
        }

        // Sumar UNA impresión
        $stmt = $db->prepare("UPDATE ads SET impressions = impressions + 1 WHERE id = ?");
        $result = $stmt->execute([$ad_id]);
        return (bool)$result;

    } catch (Exception $e) {
        error_log("❌ Error registrando impresión de anuncio: " . $e->getMessage());
        return false;
    }
}

/**
 * Verificar si la sección de anuncios fue cerrada por el usuario
 */
function isAdsSectionClosed() {
    return isset($_COOKIE['ads_section_closed']) ? $_COOKIE['ads_section_closed'] === 'true' : false;
}

/**
 * Obtener estadísticas de anuncios para admin
 */
function getAdStats($db) {
    try {
        // Verificar que la conexión a BD esté disponible
        if (!$db || !($db instanceof PDO)) {
            error_log("❌ Error: Conexión a BD no disponible en getAdStats");
            return [];
        }
        
        // Actualizar estados primero
        updateAdStatusAutomatically($db);
        
        $stmt = $db->query("
            SELECT 
                COUNT(*) as total_ads,
                SUM(CASE WHEN status = 'active' THEN 1 ELSE 0 END) as active_ads,
                SUM(CASE WHEN status = 'pending' THEN 1 ELSE 0 END) as pending_ads,
                SUM(CASE WHEN status = 'paused' THEN 1 ELSE 0 END) as paused_ads,
                SUM(CASE WHEN status = 'expired' THEN 1 ELSE 0 END) as expired_ads,
                SUM(impressions) as total_impressions,
                SUM(clicks) as total_clicks,
                ROUND(SUM(clicks) * 100.0 / NULLIF(SUM(impressions), 0), 2) as ctr,
                SUM(budget) as total_budget
            FROM ads
        ");
        return $stmt->fetch();
    } catch (Exception $e) {
        error_log("❌ Error obteniendo estadísticas de anuncios: " . $e->getMessage());
        return [];
    }
}

/**
 * Función auxiliar para formatear fechas en español
 */
function format_date_spanish($date, $format = 'd/m/Y H:i') {
    $english_days = array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday');
    $spanish_days = array('Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado', 'Domingo');
    
    $english_months = array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December');
    $spanish_months = array('Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre');
    
    $formatted = date($format, strtotime($date));
    $formatted = str_replace($english_days, $spanish_days, $formatted);
    $formatted = str_replace($english_months, $spanish_months, $formatted);
    
    return $formatted;
}

// === FUNCIONES NUEVAS PARA ADMIN DASHBOARD ===

/**
 * Obtener estadísticas rápidas para el admin dashboard
 */
function getAdminQuickStats($db) {
    try {
        $stats = $db->query("
            SELECT 
                (SELECT COUNT(*) FROM users WHERE created_at >= DATE_SUB(NOW(), INTERVAL 7 DAY)) as new_users_week,
                (SELECT COUNT(*) FROM posts WHERE created_at >= DATE_SUB(NOW(), INTERVAL 7 DAY)) as new_posts_week,
                (SELECT COUNT(*) FROM reports WHERE status = 'pending') as pending_reports,
                (SELECT COUNT(*) FROM login_attempts WHERE locked_until > NOW()) as locked_accounts,
                (SELECT COUNT(*) FROM ads WHERE status = 'active' AND start_date <= NOW() AND end_date > NOW()) as active_ads,
                (SELECT COUNT(*) FROM security_logs WHERE created_at >= DATE_SUB(NOW(), INTERVAL 24 HOUR)) as daily_logs,
                (SELECT COUNT(*) FROM users WHERE email_verified = 0) as unverified_users,
                (SELECT COUNT(*) FROM comments WHERE created_at >= DATE_SUB(NOW(), INTERVAL 7 DAY)) as new_comments_week
        ")->fetch();
        
        return $stats ?: [];
    } catch (Exception $e) {
        error_log("Error obteniendo stats admin: " . $e->getMessage());
        return [];
    }
}

/**
 * Obtener actividad reciente del sistema
 */
function getRecentSystemActivity($db, $limit = 10) {
    try {
        $stmt = $db->prepare("
            SELECT sl.*, u.username 
            FROM security_logs sl 
            LEFT JOIN users u ON sl.user_id = u.id 
            ORDER BY sl.created_at DESC 
            LIMIT ?
        ");
        $stmt->execute([$limit]);
        return $stmt->fetchAll();
    } catch (Exception $e) {
        error_log("Error obteniendo actividad reciente: " . $e->getMessage());
        return [];
    }
}

/**
 * Verificar si hay actualizaciones del sistema pendientes
 */
function checkSystemUpdates() {
    // Simulación - en producción conectaría con API de actualizaciones
    return [
        'available' => false,
        'version' => '1.2.0',
        'security' => true,
        'message' => 'Sistema actualizado'
    ];
}

/**
 * Obtener uso del sistema
 */
function getSystemUsage($db) {
    try {
        // Tamaño de la base de datos
        $size = $db->query("
            SELECT ROUND(SUM(data_length + index_length) / 1024 / 1024, 2) as size_mb 
            FROM information_schema.tables 
            WHERE table_schema = DATABASE()
        ")->fetch()['size_mb'] ?? 0;
        
        // Usuarios activos en las últimas 24h
        $active_users = $db->query("
            SELECT COUNT(DISTINCT user_id) as count 
            FROM security_logs 
            WHERE created_at >= DATE_SUB(NOW(), INTERVAL 24 HOUR)
            AND action IN ('login_success', 'post_created', 'comment_created')
        ")->fetch()['count'] ?? 0;
        
        return [
            'db_size' => $size,
            'active_users_24h' => $active_users,
            'server_time' => gmdate('Y-m-d H:i:s'),
            'php_version' => PHP_VERSION,
            'mysql_version' => $db->getAttribute(PDO::ATTR_SERVER_VERSION)
        ];
    } catch (Exception $e) {
        error_log("Error obteniendo uso del sistema: " . $e->getMessage());
        return [];
    }
}

/**
 * Obtener reportes pendientes urgentes
 */
function getUrgentReports($db, $limit = 5) {
    try {
        $stmt = $db->prepare("
            SELECT r.*, u.username as reporter_username, 
                   ru.username as target_username
            FROM reports r 
            LEFT JOIN users u ON r.reporter_id = u.id 
            LEFT JOIN users ru ON r.target_id = ru.id AND r.target_type = 'user'
            WHERE r.status = 'pending'
            ORDER BY r.created_at DESC 
            LIMIT ?
        ");
        $stmt->execute([$limit]);
        return $stmt->fetchAll();
    } catch (Exception $e) {
        error_log("Error obteniendo reportes urgentes: " . $e->getMessage());
        return [];
    }
}
?>

<?php
if (!function_exists('app_base')) {
  function app_base() {
    $script = isset($_SERVER['SCRIPT_NAME']) ? $_SERVER['SCRIPT_NAME'] : '/';
    $d = dirname($script);
    if ($d === '\\' || $d === '.' || $d === '') { $d = '/'; }
    return rtrim(str_replace('\\','/', $d), '/');
  }
}

if (!function_exists('media_url')) {
  function media_url($path) {
    if (!$path) return '';
    $base = app_base();
    if (substr($path, 0, 9) === '/uploads/' && $base !== '' && $base !== '/') {
      return $base . $path;
    }
    return $path;
  }
}

if (!function_exists('avatar_url')) {
  function avatar_url($url) { return media_url($url); }
}

if (!function_exists('avatar_img')) {
  function avatar_img($url, $username='U', $size=36, $extraClass='') {
    $u = avatar_url($url);
    $s = (int)$size;
    $initial = strtoupper(substr((string)$username, 0, 1));
    if ($u) {
      return '<img src="'.htmlspecialchars($u, ENT_QUOTES, 'UTF-8').'" class="avatar-img '.htmlspecialchars($extraClass, ENT_QUOTES, 'UTF-8').'" style="width:100%;height:100%;border-radius:50%;object-fit:cover;display:block;" alt="Avatar">';
    }
    return '<div class="avatar-initial '.htmlspecialchars($extraClass, ENT_QUOTES, 'UTF-8').'" style="width:'.$s.'px;height:'.$s.'px;border-radius:50%;display:flex;align-items:center;justify-content:center;background:#222;color:#aaa;font-weight:700;">'.htmlspecialchars($initial, ENT_QUOTES, 'UTF-8').'</div>';
  }
}
?>

<?php
if (!function_exists('fdt_madrid')) {
    /**
     * Format a UTC datetime string/timestamp into Europe/Madrid timezone.
     * @param string|int|DateTime $dt Input datetime (UTC-based if string/int)
     * @param string $format Default 'Y-m-d H:i'
     * @return string
     */
    function fdt_madrid($dt, $format = 'Y-m-d H:i') {
        try {
            if ($dt instanceof DateTime) {
                $d = clone $dt;
                $d->setTimezone(new DateTimeZone('Europe/Madrid'));
            } else {
                if (is_numeric($dt)) {
                    $d = (new DateTime('@'.intval($dt)))->setTimezone(new DateTimeZone('UTC'));
                } else {
                    $d = new DateTime((string)$dt, new DateTimeZone('UTC'));
                }
                $d->setTimezone(new DateTimeZone('Europe/Madrid'));
            }
            return $d->format($format);
        } catch (Throwable $e) {
            return '';
        }
    }
}

