class-wes-ajax.php

<?php
/**
 * Controlador AJAX para Working English System
 */

if (!defined('ABSPATH')) {
    exit;
}

class WES_Ajax {
    
    public function __construct() {
        $this->init_hooks();
    }
    
    /**
     * Inicializar hooks AJAX
     */
    private function init_hooks() {
        // AJAX para usuarios logueados
        add_action('wp_ajax_wes_get_levels_by_language', array($this, 'get_levels_by_language'));
        add_action('wp_ajax_wes_get_groups_by_filters', array($this, 'get_groups_by_filters'));
        add_action('wp_ajax_wes_search_students', array($this, 'search_students'));
        add_action('wp_ajax_wes_get_student_info', array($this, 'get_student_info'));
        add_action('wp_ajax_wes_delete_record', array($this, 'delete_record'));
        add_action('wp_ajax_wes_update_student_status', array($this, 'update_student_status'));
        add_action('wp_ajax_wes_calculate_prorated_fee', array($this, 'calculate_prorated_fee'));
        add_action('wp_ajax_wes_get_student_charges', array($this, 'get_student_charges'));
        add_action('wp_ajax_wes_validate_receipt_number', array($this, 'validate_receipt_number'));
        
        // AJAX público (si es necesario)
        add_action('wp_ajax_nopriv_wes_public_search', array($this, 'public_search'));
    }
    
    /**
     * Verificar nonce y permisos
     */
    private function verify_request($capability = 'manage_wes_system') {
        if (!wp_verify_nonce($_POST['nonce'], 'wes_nonce')) {
            wp_die(__('Error de seguridad', 'working-english-system'));
        }
        
        if (!current_user_can($capability)) {
            wp_die(__('No tienes permisos para realizar esta acción', 'working-english-system'));
        }
    }
    
    /**
     * Obtener niveles por idioma
     */
    public function get_levels_by_language() {
        $this->verify_request('view_wes_students');
        
        $language_id = intval($_POST['language_id']);
        
        if (!$language_id) {
            wp_send_json_error(__('ID de idioma inválido', 'working-english-system'));
        }
        
        global $wpdb;
        $levels = $wpdb->get_results($wpdb->prepare(
            "SELECT id, name, code FROM {$wpdb->prefix}wes_levels 
             WHERE language_id = %d AND status = 'active' 
             ORDER BY order_number",
            $language_id
        ));
        
        if ($levels) {
            wp_send_json_success($levels);
        } else {
            wp_send_json_error(__('No se encontraron niveles para este idioma', 'working-english-system'));
        }
    }
    
    /**
     * Obtener grupos por filtros
     */
    public function get_groups_by_filters() {
        $this->verify_request('view_wes_groups');
        
        $language_id = intval($_POST['language_id'] ?? 0);
        $program_id = intval($_POST['program_id'] ?? 0);
        $level_id = intval($_POST['level_id'] ?? 0);
        $branch_id = intval($_POST['branch_id'] ?? 0);
        
        global $wpdb;
        
        $where_conditions = array("g.status = 'active'");
        $where_values = array();
        
        if ($language_id) {
            $where_conditions[] = "g.language_id = %d";
            $where_values[] = $language_id;
        }
        
        if ($program_id) {
            $where_conditions[] = "g.program_id = %d";
            $where_values[] = $program_id;
        }
        
        if ($level_id) {
            $where_conditions[] = "g.level_id = %d";
            $where_values[] = $level_id;
        }
        
        if ($branch_id) {
            $where_conditions[] = "g.branch_id = %d";
            $where_values[] = $branch_id;
        }
        
        $sql = "SELECT g.id, g.code, g.name, 
                       l.name as language_name, 
                       p.name as program_name, 
                       lv.name as level_name,
                       CONCAT(t.first_name, ' ', t.last_name) as teacher_name,
                       g.current_students, g.max_students
                FROM {$wpdb->prefix}wes_groups g
                LEFT JOIN {$wpdb->prefix}wes_languages l ON g.language_id = l.id
                LEFT JOIN {$wpdb->prefix}wes_programs p ON g.program_id = p.id
                LEFT JOIN {$wpdb->prefix}wes_levels lv ON g.level_id = lv.id
                LEFT JOIN {$wpdb->prefix}wes_teachers t ON g.teacher_id = t.id
                WHERE " . implode(' AND ', $where_conditions) . "
                ORDER BY g.code";
        
        if (!empty($where_values)) {
            $groups = $wpdb->get_results($wpdb->prepare($sql, $where_values));
        } else {
            $groups = $wpdb->get_results($sql);
        }
        
        wp_send_json_success($groups);
    }
    
    /**
     * Buscar estudiantes
     */
    public function search_students() {
        $this->verify_request('view_wes_students');
        
        $search_term = sanitize_text_field($_POST['search_term'] ?? '');
        $search_type = sanitize_text_field($_POST['search_type'] ?? 'name');
        
        if (empty($search_term)) {
            wp_send_json_error(__('Término de búsqueda requerido', 'working-english-system'));
        }
        
        global $wpdb;
        
        switch ($search_type) {
            case 'code':
                $sql = "SELECT s.*, b.name as branch_name, g.name as group_name
                        FROM {$wpdb->prefix}wes_students s
                        LEFT JOIN {$wpdb->prefix}wes_branches b ON s.branch_id = b.id
                        LEFT JOIN {$wpdb->prefix}wes_groups g ON s.current_group_id = g.id
                        WHERE s.student_code LIKE %s
                        ORDER BY s.student_code";
                $students = $wpdb->get_results($wpdb->prepare($sql, '%' . $search_term . '%'));
                break;
                
            case 'email':
                $sql = "SELECT s.*, b.name as branch_name, g.name as group_name
                        FROM {$wpdb->prefix}wes_students s
                        LEFT JOIN {$wpdb->prefix}wes_branches b ON s.branch_id = b.id
                        LEFT JOIN {$wpdb->prefix}wes_groups g ON s.current_group_id = g.id
                        WHERE s.email LIKE %s
                        ORDER BY s.last_name, s.first_name";
                $students = $wpdb->get_results($wpdb->prepare($sql, '%' . $search_term . '%'));
                break;
                
            default: // name
                $sql = "SELECT s.*, b.name as branch_name, g.name as group_name
                        FROM {$wpdb->prefix}wes_students s
                        LEFT JOIN {$wpdb->prefix}wes_branches b ON s.branch_id = b.id
                        LEFT JOIN {$wpdb->prefix}wes_groups g ON s.current_group_id = g.id
                        WHERE CONCAT(s.first_name, ' ', s.last_name) LIKE %s
                           OR CONCAT(s.last_name, ' ', s.first_name) LIKE %s
                        ORDER BY s.last_name, s.first_name";
                $students = $wpdb->get_results($wpdb->prepare($sql, '%' . $search_term . '%', '%' . $search_term . '%'));
                break;
        }
        
        if ($students) {
            // Agregar badges de estado
            foreach ($students as &$student) {
                $student->status_badge = WES_Utils::get_student_status_badge($student->status);
                $student->full_name = $student->first_name . ' ' . $student->last_name;
            }
            wp_send_json_success($students);
        } else {
            wp_send_json_error(__('No se encontraron estudiantes', 'working-english-system'));
        }
    }
    
    /**
     * Obtener información completa del estudiante
     */
    public function get_student_info() {
        $this->verify_request('view_wes_students');
        
        $student_id = intval($_POST['student_id']);
        
        if (!$student_id) {
            wp_send_json_error(__('ID de estudiante inválido', 'working-english-system'));
        }
        
        global $wpdb;
        
        // Información básica del estudiante
        $student = $wpdb->get_row($wpdb->prepare(
            "SELECT s.*, b.name as branch_name, g.name as group_name, g.code as group_code
             FROM {$wpdb->prefix}wes_students s
             LEFT JOIN {$wpdb->prefix}wes_branches b ON s.branch_id = b.id
             LEFT JOIN {$wpdb->prefix}wes_groups g ON s.current_group_id = g.id
             WHERE s.id = %d",
            $student_id
        ));
        
        if (!$student) {
            wp_send_json_error(__('Estudiante no encontrado', 'working-english-system'));
        }
        
        // Historial de inscripciones
        $enrollments = $wpdb->get_results($wpdb->prepare(
            "SELECT e.*, g.name as group_name, g.code as group_code,
                    l.name as language_name, p.name as program_name, lv.name as level_name
             FROM {$wpdb->prefix}wes_enrollments e
             JOIN {$wpdb->prefix}wes_groups g ON e.group_id = g.id
             LEFT JOIN {$wpdb->prefix}wes_languages l ON g.language_id = l.id
             LEFT JOIN {$wpdb->prefix}wes_programs p ON g.program_id = p.id
             LEFT JOIN {$wpdb->prefix}wes_levels lv ON g.level_id = lv.id
             WHERE e.student_id = %d
             ORDER BY e.enrollment_date DESC",
            $student_id
        ));
        
        // Cargos pendientes
        $charges = $wpdb->get_results($wpdb->prepare(
            "SELECT * FROM {$wpdb->prefix}wes_student_charges 
             WHERE student_id = %d AND status IN ('pending', 'partial')
             ORDER BY due_date",
            $student_id
        ));
        
        // Últimos pagos
        $payments = $wpdb->get_results($wpdb->prepare(
            "SELECT p.*, c.description as charge_description
             FROM {$wpdb->prefix}wes_student_payments p
             LEFT JOIN {$wpdb->prefix}wes_student_charges c ON p.charge_id = c.id
             WHERE p.student_id = %d
             ORDER BY p.payment_date DESC
             LIMIT 5",
            $student_id
        ));
        
        $data = array(
            'student' => $student,
            'enrollments' => $enrollments,
            'charges' => $charges,
            'payments' => $payments
        );
        
        wp_send_json_success($data);
    }
    
    /**
     * Eliminar registro
     */
    public function delete_record() {
        $this->verify_request('delete_wes_data');
        
        $table = sanitize_text_field($_POST['table']);
        $record_id = intval($_POST['record_id']);
        
        if (!$record_id || !$table) {
            wp_send_json_error(__('Datos insuficientes para eliminar', 'working-english-system'));
        }
        
        // Tablas permitidas para eliminación
        $allowed_tables = array(
            'wes_students',
            'wes_teachers',
            'wes_groups',
            'wes_student_charges',
            'wes_student_payments'
        );
        
        if (!in_array($table, $allowed_tables)) {
            wp_send_json_error(__('Tabla no permitida', 'working-english-system'));
        }
        
        global $wpdb;
        
        $result = $wpdb->delete(
            $wpdb->prefix . $table,
            array('id' => $record_id),
            array('%d')
        );
        
        if ($result !== false) {
            WES_Utils::log("Registro eliminado: {$table} ID {$record_id} por usuario " . get_current_user_id());
            wp_send_json_success(__('Registro eliminado correctamente', 'working-english-system'));
        } else {
            wp_send_json_error(__('Error al eliminar el registro', 'working-english-system'));
        }
    }
    
    /**
     * Actualizar estado del estudiante
     */
    public function update_student_status() {
        $this->verify_request('manage_wes_students');
        
        $student_id = intval($_POST['student_id']);
        $new_status = sanitize_text_field($_POST['status']);
        
        $allowed_statuses = array('active', 'inactive', 'graduated', 'suspended');
        
        if (!$student_id || !in_array($new_status, $allowed_statuses)) {
            wp_send_json_error(__('Datos inválidos', 'working-english-system'));
        }
        
        global $wpdb;
        
        $result = $wpdb->update(
            $wpdb->prefix . 'wes_students',
            array('status' => $new_status),
            array('id' => $student_id),
            array('%s'),
            array('%d')
        );
        
        if ($result !== false) {
            $badge = WES_Utils::get_student_status_badge($new_status);
            wp_send_json_success(array(
                'message' => __('Estado actualizado correctamente', 'working-english-system'),
                'badge' => $badge
            ));
        } else {
            wp_send_json_error(__('Error al actualizar el estado', 'working-english-system'));
        }
    }
    
    /**
     * Calcular cuota prorrateada
     */
    public function calculate_prorated_fee() {
        $this->verify_request('manage_wes_finance');
        
        $start_date = sanitize_text_field($_POST['start_date']);
        $end_date = sanitize_text_field($_POST['end_date']);
        $monthly_fee = floatval($_POST['monthly_fee']);
        $modality = sanitize_text_field($_POST['modality']);
        
        if (!$start_date || !$end_date || !$monthly_fee) {
            wp_send_json_error(__('Datos insuficientes para el cálculo', 'working-english-system'));
        }
        
        if (!WES_Utils::validate_date($start_date) || !WES_Utils::validate_date($end_date)) {
            wp_send_json_error(__('Fechas inválidas', 'working-english-system'));
        }
        
        $prorated_amount = WES_Utils::calculate_prorated_fees($start_date, $end_date, $monthly_fee, $modality);
        
        wp_send_json_success(array(
            'prorated_amount' => $prorated_amount,
            'formatted_amount' => wes_format_currency($prorated_amount)
        ));
    }
    
    /**
     * Obtener cargos del estudiante
     */
    public function get_student_charges() {
        $this->verify_request('view_wes_finance');
        
        $student_id = intval($_POST['student_id']);
        
        if (!$student_id) {
            wp_send_json_error(__('ID de estudiante inválido', 'working-english-system'));
        }
        
        global $wpdb;
        
        $charges = $wpdb->get_results($wpdb->prepare(
            "SELECT c.*, g.name as group_name
             FROM {$wpdb->prefix}wes_student_charges c
             LEFT JOIN {$wpdb->prefix}wes_groups g ON c.group_id = g.id
             WHERE c.student_id = %d
             ORDER BY c.due_date DESC",
            $student_id
        ));
        
        if ($charges) {
            foreach ($charges as &$charge) {
                $charge->status_badge = WES_Utils::get_payment_status_badge($charge->status);
                $charge->formatted_amount = wes_format_currency($charge->final_amount);
                $charge->formatted_paid = wes_format_currency($charge->paid_amount);
                $charge->balance = $charge->final_amount - $charge->paid_amount;
                $charge->formatted_balance = wes_format_currency($charge->balance);
            }
            wp_send_json_success($charges);
        } else {
            wp_send_json_error(__('No se encontraron cargos para este estudiante', 'working-english-system'));
        }
    }
    
    /**
     * Validar número de recibo
     */
    public function validate_receipt_number() {
        $this->verify_request('process_payments');
        
        $receipt_number = sanitize_text_field($_POST['receipt_number']);
        
        if (!$receipt_number) {
            wp_send_json_error(__('Número de recibo requerido', 'working-english-system'));
        }
        
        global $wpdb;
        
        $exists = $wpdb->get_var($wpdb->prepare(
            "SELECT COUNT(*) FROM {$wpdb->prefix}wes_student_payments WHERE receipt_number = %s",
            $receipt_number
        ));
        
        if ($exists > 0) {
            wp_send_json_error(__('Este número de recibo ya existe', 'working-english-system'));
        } else {
            wp_send_json_success(__('Número de recibo disponible', 'working-english-system'));
        }
    }
    
    /**
     * Búsqueda pública (si es necesaria)
     */
    public function public_search() {
        // Implementar si se necesita búsqueda pública
        wp_send_json_error(__('Funcionalidad no disponible', 'working-english-system'));
    }
    
    /**
     * Obtener dashboard stats via AJAX
     */
    public function get_dashboard_stats() {
        $this->verify_request('manage_wes_system');
        
        global $wpdb;
        
        $stats = array();
        
        // Estudiantes por estado
        $student_stats = $wpdb->get_results(
            "SELECT status, COUNT(*) as count FROM {$wpdb->prefix}wes_students GROUP BY status"
        );
        
        foreach ($student_stats as $stat) {
            $stats['students'][$stat->status] = $stat->count;
        }
        
        // Ingresos por mes (últimos 6 meses)
        $revenue_stats = $wpdb->get_results("
            SELECT DATE_FORMAT(payment_date, '%Y-%m') as month, SUM(amount) as total
            FROM {$wpdb->prefix}wes_student_payments 
            WHERE payment_date >= DATE_SUB(CURDATE(), INTERVAL 6 MONTH)
            GROUP BY DATE_FORMAT(payment_date, '%Y-%m')
            ORDER BY month
        ");
        
        foreach ($revenue_stats as $stat) {
            $stats['revenue'][$stat->month] = floatval($stat->total);
        }
        
        // Grupos por idioma
        $group_stats = $wpdb->get_results("
            SELECT l.name, COUNT(g.id) as count
            FROM {$wpdb->prefix}wes_groups g
            JOIN {$wpdb->prefix}wes_languages l ON g.language_id = l.id
            WHERE g.status = 'active'
            GROUP BY l.id, l.name
        ");
        
        foreach ($group_stats as $stat) {
            $stats['groups'][$stat->name] = $stat->count;
        }
        
        wp_send_json_success($stats);
    }
    
    /**
     * Obtener datos para select dependiente
     */
    public function get_dependent_options() {
        $this->verify_request('view_wes_students');
        
        $parent_field = sanitize_text_field($_POST['parent_field']);
        $parent_value = intval($_POST['parent_value']);
        $target_field = sanitize_text_field($_POST['target_field']);
        
        global $wpdb;
        $options = array();
        
        switch ($parent_field . '_' . $target_field) {
            case 'language_levels':
                $options = $wpdb->get_results($wpdb->prepare(
                    "SELECT id, name, code FROM {$wpdb->prefix}wes_levels 
                     WHERE language_id = %d AND status = 'active' 
                     ORDER BY order_number",
                    $parent_value
                ));
                break;
                
            case 'branch_teachers':
                $options = $wpdb->get_results($wpdb->prepare(
                    "SELECT t.id, CONCAT(t.first_name, ' ', t.last_name) as name
                     FROM {$wpdb->prefix}wes_teachers t
                     JOIN {$wpdb->prefix}wes_groups g ON t.id = g.teacher_id
                     WHERE g.branch_id = %d AND t.status = 'active'
                     GROUP BY t.id
                     ORDER BY t.first_name, t.last_name",
                    $parent_value
                ));
                break;
                
            case 'teacher_groups':
                $options = $wpdb->get_results($wpdb->prepare(
                    "SELECT id, code as name, name as description
                     FROM {$wpdb->prefix}wes_groups 
                     WHERE teacher_id = %d AND status = 'active'
                     ORDER BY code",
                    $parent_value
                ));
                break;
        }
        
        wp_send_json_success($options);
    }
    
    /**
     * Exportar datos
     */
    public function export_data() {
        $this->verify_request('export_wes_data');
        
        $export_type = sanitize_text_field($_POST['export_type']);
        $format = sanitize_text_field($_POST['format']) ?: 'csv';
        
        global $wpdb;
        
        switch ($export_type) {
            case 'students':
                $data = $wpdb->get_results("
                    SELECT s.student_code, s.first_name, s.last_name, s.email, s.phone,
                           s.registration_date, s.status, b.name as branch, g.name as current_group
                    FROM {$wpdb->prefix}wes_students s
                    LEFT JOIN {$wpdb->prefix}wes_branches b ON s.branch_id = b.id
                    LEFT JOIN {$wpdb->prefix}wes_groups g ON s.current_group_id = g.id
                    ORDER BY s.student_code
                ", ARRAY_A);
                
                $filename = 'estudiantes_' . date('Y-m-d') . '.csv';
                $headers = array('Código', 'Nombre', 'Apellido', 'Email', 'Teléfono', 'Fecha Registro', 'Estado', 'Sede', 'Grupo Actual');
                break;
                
            case 'payments':
                $data = $wpdb->get_results("
                    SELECT p.receipt_number, CONCAT(s.first_name, ' ', s.last_name) as student_name,
                           s.student_code, p.amount, p.payment_method, p.payment_date,
                           c.description as charge_description
                    FROM {$wpdb->prefix}wes_student_payments p
                    JOIN {$wpdb->prefix}wes_students s ON p.student_id = s.id
                    LEFT JOIN {$wpdb->prefix}wes_student_charges c ON p.charge_id = c.id
                    ORDER BY p.payment_date DESC
                ", ARRAY_A);
                
                $filename = 'pagos_' . date('Y-m-d') . '.csv';
                $headers = array('Recibo', 'Estudiante', 'Código', 'Monto', 'Método', 'Fecha', 'Descripción');
                break;
                
            default:
                wp_send_json_error(__('Tipo de exportación no válido', 'working-english-system'));
        }
        
        if ($format === 'csv') {
            WES_Utils::export_to_csv($data, $filename, $headers);
        } else {
            wp_send_json_error(__('Formato no soportado', 'working-english-system'));
        }
    }
}