<?php
// /cron_tasks.php
// Punto de entrada para todas las tareas de mantenimiento y limpieza programadas.
// ARCHIVO CORREGIDO: Añadida la lógica de Backup Semanal

// Solo permitir ejecución vía AJAX (seguridad básica)
if (empty($_POST['ajax'])) {
    http_response_code(403);
    die('Acceso denegado.');
}

require_once 'db.php';
require_once 'mail_helpers.php'; // ★★★ AÑADIDO PARA EL ENVÍO DE EMAIL ★★★
require_once 'backup_utils.php'; // Para acciones de backup

// --- ★★★ INICIO DE LA CORRECCIÓN ★★★ ---
// Añadimos este 'require' para tener acceso a la función 'calculate_adherence_percentage'
require_once 'patient_functions.php';
// --- ★★★ FIN DE LA CORRECCIÓN ★★★ ---

// Asumimos que la función log_audit_action está definida en db.php o un include necesario

// --- 1. GUARDIÁN GENERAL (Lógica del Cron Simulado) ---
// Evita ejecuciones múltiples en un corto periodo para tareas generales (notificaciones, tratamientos).
$cache_dir = __DIR__ . '/cache';
if (!is_dir($cache_dir)) { @mkdir($cache_dir, 0755, true); }
$cron_check_file = $cache_dir . '/last_cron_run_flag.txt';

// Intervalo para TAREAS GENERALES (Ej: 3 horas)
$max_time_gap_seconds = 3 * 3600;
$run_cron_logic = false;

if (!file_exists($cron_check_file) || filemtime($cron_check_file) < (time() - $max_time_gap_seconds)) {
    $run_cron_logic = true;
}

// Si no toca ejecutar, salimos silenciosamente
if (!$run_cron_logic) {
    echo json_encode(['status' => 'skipped', 'message' => 'Cron general no requerido en este momento.']);
    exit;
}

// Si toca ejecutar, actualizamos el flag INMEDIATAMENTE para evitar duplicados
if (!@touch($cron_check_file)) {
    error_log("Error: No se pudo actualizar el timestamp de '$cron_check_file'. Verifica permisos.");
}


// --- 1.b GUARDIANES ESPECÍFICOS (SEMANALES) ---
$audit_purge_check_file = $cache_dir . '/last_audit_purge_flag.txt';
$weekly_summary_check_file = $cache_dir . '/last_weekly_summary_flag.txt';
// ★★★ NUEVO GUARDIÁN DE BACKUP ★★★
$backup_check_file = $cache_dir . '/last_backup_flag.txt';

// ★★★ INICIO MODIFICACIÓN (NUEVO GUARDIÁN DIARIO) ★★★
$token_purge_check_file = $cache_dir . '/last_token_purge_flag.txt';
// ★★★ FIN MODIFICACIÓN ★★★


// Intervalo para PURGA DE LOGS: 7 días
$audit_purge_time_gap = 7 * 24 * 3600;
$run_audit_purge = false;

if (!file_exists($audit_purge_check_file) || filemtime($audit_purge_check_file) < (time() - $audit_purge_time_gap)) {
    $run_audit_purge = true;
}

// Intervalo para RESUMEN SEMANAL: 7 días
$weekly_summary_time_gap = 7 * 24 * 3600;
$run_weekly_summary = false;

if (!file_exists($weekly_summary_check_file) || filemtime($weekly_summary_check_file) < (time() - $weekly_summary_time_gap)) {
    $run_weekly_summary = true;
}

// ★★★ NUEVA LÓGICA DE GUARDIÁN DE BACKUP ★★★
// Intervalo para BACKUP: 7 días
$backup_time_gap = 7 * 24 * 3600;
$run_backup = false;
if (!file_exists($backup_check_file) || filemtime($backup_check_file) < (time() - $backup_time_gap)) {
    $run_backup = true;
}

// ★★★ INICIO MODIFICACIÓN (NUEVA LÓGICA DE GUARDIÁN) ★★★
// Intervalo para PURGA DE TOKENS: 1 día
$token_purge_time_gap = 24 * 3600;
$run_token_purge = false;

if (!file_exists($token_purge_check_file) || filemtime($token_purge_check_file) < (time() - $token_purge_time_gap)) {
    $run_token_purge = true;
}
// ★★★ FIN MODIFICACIÓN ★★★


// --- INICIO DE TAREAS DE FONDO ---
$report = [
    'status' => 'success',
    'treatments_updated' => 0,
    'notifications_generated' => 0,
    'notifications_purged_read' => 0,
    'notifications_purged_old' => 0,
    'audit_logs_purged' => 0,
    'weekly_summaries_sent' => 0,
    'backup_created_file' => null, // ★ NUEVO CAMPO DE REPORTE ★
    'tokens_purged' => 0 //           ★★★ AÑADIR ESTA LÍNEA ★★★
];

try {
    $db->beginTransaction();

    // --- ======================================================= ---
    // --- ★★★ INICIO TAREA 2 (LÓGICA DE GRÁFICOS AÑADIDA) ★★★ ---
    // --- ======================================================= ---
    $stmt_update_treatments = $db->prepare(
        "UPDATE tratamientos
         SET status = ?, realizacion_percent = ?
         WHERE id = ?"
    );

    $today_str = date('Y-m-d');
    $treatments_updated_count = 0;

    // a) Actualizar 'En curs' que han finalizado
    $stmt_ended = $db->prepare(
        "SELECT id FROM tratamientos
         WHERE status = 'En curs' AND end_date < :today"
    );
    $stmt_ended->execute([':today' => $today_str]);
    $treatments_to_end = $stmt_ended->fetchAll(PDO::FETCH_COLUMN);

    foreach ($treatments_to_end as $treatment_id) {
        $adherence = calculate_adherence_percentage($treatment_id, $db);
        // Marcar como 'Completat' y guardar adherencia
        $stmt_update_treatments->execute(['Completat', $adherence, $treatment_id]);
        $treatments_updated_count++;
    }

    // b) Actualizar 'Programat' que deben empezar
    $stmt_start = $db->prepare(
        "UPDATE tratamientos
         SET status = 'En curs'
         WHERE status = 'Programat' AND start_date <= :today"
    );
    $stmt_start->execute([':today' => $today_str]);
    $treatments_updated_count += $stmt_start->rowCount();

    // c) Recalcular adherencia de los que siguen 'En curs'
    // (Esto es importante para los gráficos del fisio)
    $stmt_in_progress = $db->prepare(
        "SELECT id FROM tratamientos
         WHERE status = 'En curs'"
    );
    $stmt_in_progress->execute();
    $treatments_in_progress = $stmt_in_progress->fetchAll(PDO::FETCH_COLUMN);

    $stmt_update_percent = $db->prepare(
        "UPDATE tratamientos
         SET realizacion_percent = ?
         WHERE id = ?"
    );

    foreach ($treatments_in_progress as $treatment_id) {
        $adherence = calculate_adherence_percentage($treatment_id, $db);
        // Solo actualizamos el % (no el estado)
        $stmt_update_percent->execute([$adherence, $treatment_id]);
    }

    $report['treatments_updated'] = $treatments_updated_count;
    // --- ======================================================= ---
    // --- ★★★ FIN TAREA 2 ★★★ ---
    // --- ======================================================= ---


    // --- 3. GENERAR NUEVAS NOTIFICACIONES ---
    // ... (Lógica de generación de notificaciones va aquí) ...

    // --- 4. PURGAR NOTIFICACIONES ANTIGUAS ---

    // ★★★ CORRECCIÓN 1: Sintaxis MySQL para 30 días (YA ESTABA BIEN) ★★★
    // Borra notificaciones LEÍDAS de más de 30 días
    $stmt_purge_read = $db->prepare("
        DELETE FROM notificaciones
        WHERE leido_en IS NOT NULL
          AND leido_en < DATE_SUB(NOW(), INTERVAL 30 DAY)
    ");
    $stmt_purge_read->execute();
    $report['notifications_purged_read'] = $stmt_purge_read->rowCount();

    // ★★★ CORRECCIÓN 2: Sintaxis MySQL para 90 días (YA ESTABA BIEN) ★★★
    // Borra CUALQUIER notificación de más de 90 días
    $stmt_purge_all_old = $db->prepare("
        DELETE FROM notificaciones
        WHERE fecha_creacion < DATE_SUB(NOW(), INTERVAL 90 DAY)
    ");
    $stmt_purge_all_old->execute();
    $report['notifications_purged_old'] = $stmt_purge_all_old->rowCount();


    // --- 5. PURGAR REGISTROS DE AUDITORÍA (A7) (EJECUCIÓN SEMANAL) ★ MODIFICADO ★ ---
    if ($run_audit_purge) {

        // PERIODO DE RETENCIÓN DE LOGS: 2 AÑOS (730 días)
        $audit_retention_period_days = 365 * 2;

        // ★★★ CORRECCIÓN 3: Sintaxis MySQL para 'X' días (YA ESTABA BIEN) ★★★
        $stmt_purge_audit = $db->prepare("
            DELETE FROM log_auditoria
            WHERE timestamp < DATE_SUB(NOW(), INTERVAL ? DAY)
        ");
        $stmt_purge_audit->execute([$audit_retention_period_days]);

        $rows_deleted = $stmt_purge_audit->rowCount();
        $report['audit_logs_purged'] = $rows_deleted;

        // Actualizamos el flag de la purga SEMANAL para que no se ejecute de nuevo hasta la próxima semana
        if (!@touch($audit_purge_check_file)) {
            error_log("Advertencia: No se pudo actualizar el timestamp de la purga de logs.");
        }

        // Registro de la acción de purga
        if ($rows_deleted > 0) {
            // Actor: Sistema (o el usuario logueado que disparó el cron en ese momento)
            log_audit_action('AUDIT_LOG_PURGED', null, $rows_deleted, "Registros de auditoría más antiguos de 2 años eliminados. Ejecución Semanal.");
        }
    }

    // ★★★ INICIO MODIFICACIÓN (NUEVA TAREA DE PURGA DE TOKENS) ★★★
    // --- 5b. PURGAR TOKENS DE RESETEO CADUCADOS (EJECUCIÓN DIARIA) ---
    if ($run_token_purge) {

        // Borra todos los tokens donde la fecha de expiración sea anterior a este momento.
        $stmt_purge_tokens = $db->prepare("
            DELETE FROM password_resets
            WHERE expires_at < NOW()
        ");

        $stmt_purge_tokens->execute();
        $rows_deleted = $stmt_purge_tokens->rowCount();
        $report['tokens_purged'] = $rows_deleted;

        // Actualizamos el flag diario
        if (!@touch($token_purge_check_file)) {
            error_log("Advertencia: No se pudo actualizar el timestamp de la purga de tokens.");
        }

        // (Opcional) Registrar en auditoría que la limpieza se ha hecho
        if ($rows_deleted > 0) {
            log_audit_action('TOKENS_PURGED', null, $rows_deleted, "Tokens de reseteo caducados eliminados. Ejecución Diaria.");
        }
    }
    // ★★★ FIN MODIFICACIÓN ★★★


    // --- ★★★ 6. ENVIAR RESUMEN SEMANAL POR EMAIL (TAREA SEMANAL) ★★★ ---
    if ($run_weekly_summary) {

        // --- ======================================================= ---
        // --- ★★★ INICIO DE LA CORRECCIÓN 1: DETECCIÓN DINÁMICA DE URL ★★★ ---
        // --- ======================================================= ---
        $protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' || $_SERVER['SERVER_PORT'] == 443) ? "https://" : "http://";
        $domain = $_SERVER['HTTP_HOST'];
        // Detectar carpeta actual y eliminar barras finales
        $path = rtrim(dirname($_SERVER['SCRIPT_NAME']), '/');
        $base_url = $protocol . $domain . $path . '/';
        // --- ★ FIN DE LA CORRECCIÓN 1 ★ ---
        // --- ======================================================= ---


        // --- ★★★ INICIO DE LA MODIFICACIÓN (COMPROBAR SWITCH SEMANAL) ★★★ ---
        // --- ======================================================= ---

        $stmt_check_weekly = $db->prepare("SELECT is_enabled FROM email_settings WHERE setting_name = 'weekly_summary' LIMIT 1");
        $stmt_check_weekly->execute();

        // Comprobamos si el interruptor existe y está en '1'
        if ($stmt_check_weekly->fetchColumn() != 1) {

            // El interruptor está DESACTIVADO.
            // Marcamos la tarea como 'deshabilitada' en el reporte.
            $report['weekly_summaries_sent'] = 'Deshabilitado';

            // Igualmente actualizamos el flag semanal para que no lo intente
            // de nuevo hasta la próxima semana.
            if (!@touch($weekly_summary_check_file)) {
                error_log("Advertencia: No se pudo actualizar el timestamp del resumen semanal (estaba deshabilitado).");
            }

        } else {
            // El interruptor está ACTIVADO. Procedemos con la lógica normal de envío.

            // 1. Obtener la lista de pacientes activos con al menos un tratamiento EN CURS
            $stmt_pacients = $db->query("
                SELECT DISTINCT c.id, c.email, c.nombre
                FROM cuentas c
                JOIN tratamientos t ON c.id = t.paciente_id
                WHERE c.rol = 'paciente' AND c.status = 'activo' AND t.status = 'En curs'
            ");
            $pacients_to_notify = $stmt_pacients->fetchAll(PDO::FETCH_ASSOC);

            $email_sent_count = 0;

            // 2. Definir imagen (con las nuevas reglas)
            $logo_path = __DIR__ . '/logos/img_defecte.png';
            $embedded_logo = [['path' => $logo_path, 'cid' => 'logo_avant']];
            $subject = "El teu resum setmanal de progrés";

            $date_one_week_ago = date('Y-m-d', strtotime('-7 days'));
            $date_today = date('Y-m-d');

            foreach ($pacients_to_notify as $pacient) {

                // --- CÁLCULO DE PROGRESO DE LA ÚLTIMA SEMANA ---
                // (Esta es una versión simplificada)

                // a) Evoluciones registradas la última semana
                $stmt_evo_count = $db->prepare("
                    SELECT COUNT(ev.id)
                    FROM tratamiento_evolucion ev
                    JOIN tratamiento_ejercicios te ON ev.tratamiento_ejercicio_id = te.id
                    JOIN tratamientos t ON te.tratamiento_id = t.id
                    WHERE t.paciente_id = :pacient_id
                    AND ev.fecha_realizacion BETWEEN :start_date AND :end_date
                ");
                $stmt_evo_count->execute([':pacient_id' => $pacient['id'], ':start_date' => $date_one_week_ago, ':end_date' => $date_today]);
                $total_records = $stmt_evo_count->fetchColumn();

                // b) Adherencia General del tratamiento más activo
                // Necesitamos la función calculate_adherence_percentage que ya existe en el código
                $stmt_adherence = $db->prepare("
                    SELECT id
                    FROM tratamientos
                    WHERE paciente_id = :pacient_id AND status = 'En curs'
                    ORDER BY start_date DESC
                    LIMIT 1
                ");
                $stmt_adherence->execute([':pacient_id' => $pacient['id']]);
                $most_active_treatment_id = $stmt_adherence->fetchColumn();

                $adherence_percent = 0;
                if ($most_active_treatment_id) {
                    // Aquí deberías tener la función calculate_adherence_percentage definida en el scope
                    // Si está en 'backup_utils.php', necesita estar en el scope
                    // Por ahora, asumimos que existe y es accesible (como en treatments.php)
                    // Usamos 0 como valor por defecto si falla el cálculo aquí.
                     try {
                         // Asumimos que calculate_adherence_percentage está en db.php o backup_utils.php
                         if (function_exists('calculate_adherence_percentage')) {
                             $adherence_percent = calculate_adherence_percentage((int)$most_active_treatment_id, $db);
                         } else {
                             // Fallback si la función no se ha cargado (ej. movida a dashboard.php)
                             error_log("Error CRON: calculate_adherence_percentage no está definida.");
                             $adherence_percent = 0;
                         }
                     } catch (Exception $e) {
                          error_log("Error de cálculo de adherencia en CRON: " . $e->getMessage());
                          $adherence_percent = 0;
                     }
                }
                // --- FIN CÁLCULO DE PROGRESO ---

                // --- ★★★ INICIO DE LA CORRECCIÓN 2: USO DE $base_url ★★★ ---
                $body_paciente = "
                <div style='font-family: Arial, sans-serif; line-height: 1.6; max-width: 600px; margin: auto; padding: 20px; border: 1px solid #ddd; border-radius: 8px;'>
                    <div style='text-align: center; margin-bottom: 20px;'>
                        <img src='cid:logo_avant' alt='Logo de la Clínica' style='width: 250px; height: auto;'>
                    </div>
                    <h1 style='color: #333; text-align: center; font-size: 24px;'>Hola, " . htmlspecialchars($pacient['nombre']) . "!</h1>
                    <p>Aquí tens un resum del teu progrés a AVANT ONLINE durant l'última setmana.</p>
                    <ul style='list-style-type: none; padding-left: 0; background-color: #f9f9f9; border: 1px solid #eee; padding: 15px; border-radius: 5px;'>
                        <li><strong>Registre d'Evolucions:</strong> Has realitzat <strong>{$total_records}</strong> sessions d'exercicis aquesta setmana.</li>
                        <li><strong>Adherència Global:</strong> El teu nivell d'adherència global és del <strong>{$adherence_percent}%</strong>.</li>
                        " . ($adherence_percent < 50 ? "<li style='color: #d9534f; font-weight: bold;'>⚠️ Podries esforçar-te més! Intenta completar la teua pauta diària.</li>" : "<li style='color: #198754;'>🎉 Continua amb aquest ritme! Molt bona feina!</li>") . "
                    </ul>
                    <p>Recorda, la constància és clau per a la teua recuperació.</p>
                    <p style='text-align: center; margin-top: 30px;'>
                        <a href='" . $base_url . "patient_dashboard.php' style='background-color: #0d6efd; color: white; padding: 12px 20px; text-decoration: none; border-radius: 5px; font-weight: bold;'>
                            Revisa els teus Exercicis
                        </a>
                    </p>
                </div>
                ";
                // --- ★★★ FIN DE LA CORRECCIÓN 2 ★★★ ---

                if (send_platform_email($pacient['email'], $subject, $body_paciente, true, $embedded_logo)) {
                    $email_sent_count++;
                }
            } // Fin del foreach

            $report['weekly_summaries_sent'] = $email_sent_count;

            // Actualizamos el flag de la purga SEMANAL para que no se ejecute de nuevo hasta la próxima semana
            if (!@touch($weekly_summary_check_file)) {
                error_log("Advertencia: No se pudo actualizar el timestamp del resumen semanal.");
            }

        } // --- ★★★ ESTE ES EL CIERRE DEL 'ELSE' QUE HE AÑADIDO ★★★ ---
    }
    // --- ★★★ FIN DE LA MODIFICACIÓN ★★★ ---


    // --- ★★★ 7. EJECUTAR BACKUP SEMANAL (TAREA SEMANAL) ★★★ ---
    if ($run_backup) {

        $backupDir = __DIR__ . '/_backups';
        // La función ya está incluida desde 'backup_utils.php'
        $result = backupDatabase(null, $backupDir);

        if ($result['status'] === 'success') {
            $report['backup_created_file'] = $result['message']; // Guardamos el nombre del archivo

            // Actualizamos el flag del backup SEMANAL
            if (!@touch($backup_check_file)) {
                error_log("Advertencia: No se pudo actualizar el timestamp del backup.");
            }
        } else {
            // Si el backup falla, NO actualizamos el timestamp.
            // Así, lo intentará de nuevo en la próxima ejecución del cron.
            error_log("Error CRON: El backup automático falló: " . $result['message']);
        }
    }
    // --- ★★★ FIN TAREA 7 ★★★ ---


    // --- FIN DE TAREAS ---
    $db->commit();

    header('Content-Type: application/json');
    echo json_encode($report);

} catch (Exception $e) {
    if ($db->inTransaction()) $db->rollBack();
    error_log("Error en cron_tasks.php: " . $e->getMessage());
    http_response_code(500);
    echo json_encode(['status' => 'error', 'message' => $e->getMessage()]);
}

exit;
?>
