class-wes-utils.php

<?php
/**
 * Clase de utilidades para Working English System
 */

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

class WES_Utils {
    
    /**
     * Generar código único para estudiante
     */
    public static function generate_student_code($branch_id = null) {
        global $wpdb;
        
        // Obtener código de sede
        $branch_code = 'MAIN';
        if ($branch_id) {
            $branch_code = $wpdb->get_var($wpdb->prepare(
                "SELECT code FROM {$wpdb->prefix}wes_branches WHERE id = %d",
                $branch_id
            ));
        }
        
        // Año actual
        $year = date('Y');
        
        // Obtener el siguiente número secuencial
        $last_number = $wpdb->get_var($wpdb->prepare(
            "SELECT MAX(CAST(SUBSTRING(student_code, -4) AS UNSIGNED)) 
             FROM {$wpdb->prefix}wes_students 
             WHERE student_code LIKE %s",
            $branch_code . $year . '%'
        ));
        
        $next_number = str_pad(($last_number + 1), 4, '0', STR_PAD_LEFT);
        
        return $branch_code . $year . $next_number;
    }
    
    /**
     * Generar código único para grupo
     */
    public static function generate_group_code($language_id, $program_id, $level_id, $year = null) {
        global $wpdb;
        
        if (!$year) {
            $year = date('Y');
        }
        
        // Obtener códigos
        $language_code = $wpdb->get_var($wpdb->prepare(
            "SELECT code FROM {$wpdb->prefix}wes_languages WHERE id = %d",
            $language_id
        ));
        
        $program_code = $wpdb->get_var($wpdb->prepare(
            "SELECT code FROM {$wpdb->prefix}wes_programs WHERE id = %d",
            $program_id
        ));
        
        $level_code = $wpdb->get_var($wpdb->prepare(
            "SELECT code FROM {$wpdb->prefix}wes_levels WHERE id = %d",
            $level_id
        ));
        
        // Formato: EN-GE-A1-2024-001
        $base_code = $language_code . '-' . $program_code . '-' . $level_code . '-' . $year;
        
        // Obtener siguiente número correlativo
        $last_number = $wpdb->get_var($wpdb->prepare(
            "SELECT MAX(CAST(SUBSTRING(code, -3) AS UNSIGNED)) 
             FROM {$wpdb->prefix}wes_groups 
             WHERE code LIKE %s",
            $base_code . '%'
        ));
        
        $next_number = str_pad(($last_number + 1), 3, '0', STR_PAD_LEFT);
        
        return $base_code . '-' . $next_number;
    }
    
    /**
     * Generar número de recibo
     */
    public static function generate_receipt_number() {
        global $wpdb;
        
        $year = date('Y');
        $month = date('m');
        
        // Formato: REC-202501-0001
        $prefix = 'REC-' . $year . $month . '-';
        
        $last_number = $wpdb->get_var($wpdb->prepare(
            "SELECT MAX(CAST(SUBSTRING(receipt_number, -4) AS UNSIGNED)) 
             FROM {$wpdb->prefix}wes_student_payments 
             WHERE receipt_number LIKE %s",
            $prefix . '%'
        ));
        
        $next_number = str_pad(($last_number + 1), 4, '0', STR_PAD_LEFT);
        
        return $prefix . $next_number;
    }
    
    /**
     * Calcular cuotas prorrateadas
     */
    public static function calculate_prorated_fees($start_date, $end_date, $monthly_fee, $modality = 'presencial') {
        $start = new DateTime($start_date);
        $end = new DateTime($end_date);
        
        // Días de clase por modalidad
        $class_days_per_week = array(
            'presencial' => 5, // Lunes a viernes
            'virtual' => 3,    // 3 días por semana
            'hibrida' => 4     // 4 días por semana
        );
        
        $days_per_week = isset($class_days_per_week[$modality]) ? 
                        $class_days_per_week[$modality] : 5;
        
        // Calcular días hábiles totales
        $total_class_days = self::calculate_business_days($start, $end, $days_per_week);
        
        // Días en el mes
        $days_in_month = $start->format('t');
        $business_days_in_month = ($days_in_month / 7) * $days_per_week;
        
        // Calcular proporción
        $daily_rate = $monthly_fee / $business_days_in_month;
        $prorated_amount = $daily_rate * $total_class_days;
        
        return round($prorated_amount, 2);
    }
    
    /**
     * Calcular días hábiles entre fechas
     */
    public static function calculate_business_days($start_date, $end_date, $days_per_week = 5) {
        if (is_string($start_date)) {
            $start_date = new DateTime($start_date);
        }
        if (is_string($end_date)) {
            $end_date = new DateTime($end_date);
        }
        
        $interval = $start_date->diff($end_date);
        $total_days = $interval->days;
        $weeks = floor($total_days / 7);
        $remaining_days = $total_days % 7;
        
        // Calcular días de clase
        $class_days = $weeks * $days_per_week;
        
        // Agregar días restantes (simplificado)
        $class_days += min($remaining_days, $days_per_week);
        
        return $class_days;
    }
    
    /**
     * Validar email
     */
    public static function validate_email($email) {
        return filter_var($email, FILTER_VALIDATE_EMAIL) !== false;
    }
    
    /**
     * Validar teléfono
     */
    public static function validate_phone($phone) {
        // Remover espacios y caracteres especiales
        $phone = preg_replace('/[^0-9+]/', '', $phone);
        
        // Debe tener al menos 8 dígitos
        return strlen($phone) >= 8;
    }
    
    /**
     * Formatear nombre propio
     */
    public static function format_name($name) {
        return ucwords(strtolower(trim($name)));
    }
    
    /**
     * Sanitizar código
     */
    public static function sanitize_code($code) {
        return strtoupper(preg_replace('/[^A-Z0-9-]/', '', $code));
    }
    
    /**
     * Obtener estado del estudiante con badge HTML
     */
    public static function get_student_status_badge($status) {
        $badges = array(
            'active' => '<span class="badge bg-success">Activo</span>',
            'inactive' => '<span class="badge bg-secondary">Inactivo</span>',
            'graduated' => '<span class="badge bg-primary">Graduado</span>',
            'suspended' => '<span class="badge bg-danger">Suspendido</span>'
        );
        
        return isset($badges[$status]) ? $badges[$status] : '<span class="badge bg-warning">Desconocido</span>';
    }
    
    /**
     * Obtener estado del grupo con badge HTML
     */
    public static function get_group_status_badge($status) {
        $badges = array(
            'active' => '<span class="badge bg-success">Activo</span>',
            'inactive' => '<span class="badge bg-secondary">Inactivo</span>',
            'completed' => '<span class="badge bg-primary">Completado</span>',
            'cancelled' => '<span class="badge bg-danger">Cancelado</span>'
        );
        
        return isset($badges[$status]) ? $badges[$status] : '<span class="badge bg-warning">Desconocido</span>';
    }
    
    /**
     * Obtener estado del pago con badge HTML
     */
    public static function get_payment_status_badge($status) {
        $badges = array(
            'pending' => '<span class="badge bg-warning">Pendiente</span>',
            'partial' => '<span class="badge bg-info">Parcial</span>',
            'paid' => '<span class="badge bg-success">Pagado</span>',
            'overdue' => '<span class="badge bg-danger">Vencido</span>',
            'cancelled' => '<span class="badge bg-secondary">Cancelado</span>'
        );
        
        return isset($badges[$status]) ? $badges[$status] : '<span class="badge bg-dark">Desconocido</span>';
    }
    
    /**
     * Generar paginación HTML
     */
    public static function generate_pagination($current_page, $total_pages, $base_url) {
        if ($total_pages <= 1) {
            return '';
        }
        
        $pagination = '<nav aria-label="Paginación"><ul class="pagination justify-content-center">';
        
        // Botón anterior
        if ($current_page > 1) {
            $prev_url = add_query_arg('paged', $current_page - 1, $base_url);
            $pagination .= '<li class="page-item"><a class="page-link" href="' . esc_url($prev_url) . '">« Anterior</a></li>';
        }
        
        // Números de página
        $start = max(1, $current_page - 2);
        $end = min($total_pages, $current_page + 2);
        
        for ($i = $start; $i <= $end; $i++) {
            $active = ($i == $current_page) ? ' active' : '';
            $page_url = add_query_arg('paged', $i, $base_url);
            $pagination .= '<li class="page-item' . $active . '"><a class="page-link" href="' . esc_url($page_url) . '">' . $i . '</a></li>';
        }
        
        // Botón siguiente
        if ($current_page < $total_pages) {
            $next_url = add_query_arg('paged', $current_page + 1, $base_url);
            $pagination .= '<li class="page-item"><a class="page-link" href="' . esc_url($next_url) . '">Siguiente »</a></li>';
        }
        
        $pagination .= '</ul></nav>';
        
        return $pagination;
    }
    
    /**
     * Exportar datos a CSV
     */
    public static function export_to_csv($data, $filename, $headers = array()) {
        if (empty($data)) {
            return false;
        }
        
        // Headers para descarga
        header('Content-Type: text/csv; charset=utf-8');
        header('Content-Disposition: attachment; filename="' . $filename . '"');
        header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
        header('Pragma: public');
        
        $output = fopen('php://output', 'w');
        
        // BOM para UTF-8
        fprintf($output, chr(0xEF).chr(0xBB).chr(0xBF));
        
        // Headers si se proporcionan
        if (!empty($headers)) {
            fputcsv($output, $headers);
        } else {
            // Usar las claves del primer elemento como headers
            $first_row = reset($data);
            if (is_array($first_row) || is_object($first_row)) {
                $headers = is_object($first_row) ? array_keys(get_object_vars($first_row)) : array_keys($first_row);
                fputcsv($output, $headers);
            }
        }
        
        // Datos
        foreach ($data as $row) {
            if (is_object($row)) {
                $row = get_object_vars($row);
            }
            fputcsv($output, $row);
        }
        
        fclose($output);
        exit;
    }
    
    /**
     * Limpiar y validar datos de entrada
     */
    public static function sanitize_input($data, $type = 'text') {
        switch ($type) {
            case 'email':
                return sanitize_email($data);
            case 'url':
                return esc_url_raw($data);
            case 'int':
                return intval($data);
            case 'float':
                return floatval($data);
            case 'textarea':
                return sanitize_textarea_field($data);
            case 'html':
                return wp_kses_post($data);
            default:
                return sanitize_text_field($data);
        }
    }
    
    /**
     * Verificar si una fecha es válida
     */
    public static function validate_date($date, $format = 'Y-m-d') {
        $d = DateTime::createFromFormat($format, $date);
        return $d && $d->format($format) === $date;
    }
    
    /**
     * Calcular edad a partir de fecha de nacimiento
     */
    public static function calculate_age($birth_date) {
        if (!self::validate_date($birth_date)) {
            return null;
        }
        
        $birth = new DateTime($birth_date);
        $today = new DateTime();
        $age = $today->diff($birth);
        
        return $age->y;
    }
    
    /**
     * Logging personalizado
     */
    public static function log($message, $level = 'info') {
        if (!defined('WP_DEBUG') || !WP_DEBUG) {
            return;
        }
        
        $log_entry = '[' . date('Y-m-d H:i:s') . '] [WES] [' . strtoupper($level) . '] ' . $message . PHP_EOL;
        
        $log_file = WP_CONTENT_DIR . '/wes-debug.log';
        file_put_contents($log_file, $log_entry, FILE_APPEND | LOCK_EX);
    }
    
    /**
     * Obtener configuración con valor por defecto
     */
    public static function get_option($option_name, $default = '') {
        return get_option('wes_' . $option_name, $default);
    }
    
    /**
     * Guardar configuración
     */
    public static function update_option($option_name, $value) {
        return update_option('wes_' . $option_name, $value);
    }
}