<?php
/**
 * Session Service
 *
 * Handles user session management, security and monitoring
 *
 * @package Care_API
 * @subpackage Services
 * @version    1.0.0
 * @author     Descomplicar® <dev@descomplicar.pt>
 * @link       https://descomplicar.pt
 * @since      1.0.0
 */

namespace Care_API\Services;

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

/**
 * Class Session_Service
 *
 * Session management and security monitoring for Care API
 *
 * @since 1.0.0
 */
class Session_Service {

    /**
     * Maximum concurrent sessions per user
     *
     * @var int
     */
    private static $max_concurrent_sessions = 3;

    /**
     * Session timeout (in seconds) - 30 minutes
     *
     * @var int
     */
    private static $session_timeout = 1800;

    /**
     * Maximum failed login attempts
     *
     * @var int
     */
    private static $max_failed_attempts = 5;

    /**
     * Lockout duration (in seconds) - 15 minutes
     *
     * @var int
     */
    private static $lockout_duration = 900;

    /**
     * Initialize the session service
     *
     * @since 1.0.0
     */
    public static function init() {
        // Hook into authentication events
        add_action( 'kivicare_user_authenticated', array( self::class, 'on_user_authenticated' ), 10, 2 );
        add_action( 'kivicare_user_logout', array( self::class, 'on_user_logout' ), 10, 1 );
        add_action( 'kivicare_failed_login', array( self::class, 'on_failed_login' ), 10, 1 );

        // Cleanup expired sessions
        add_action( 'kivicare_cleanup_sessions', array( self::class, 'cleanup_expired_sessions' ) );
        
        // Schedule cleanup if not already scheduled
        if ( ! wp_next_scheduled( 'kivicare_cleanup_sessions' ) ) {
            wp_schedule_event( time(), 'hourly', 'kivicare_cleanup_sessions' );
        }

        // Monitor session activity
        add_action( 'init', array( self::class, 'monitor_session_activity' ) );
    }

    /**
     * Create new session for user
     *
     * @param int    $user_id    User ID
     * @param string $ip_address IP address
     * @param string $user_agent User agent
     * @return string Session ID
     * @since 1.0.0
     */
    public static function create_session( $user_id, $ip_address, $user_agent ) {
        // Generate unique session ID
        $session_id = wp_generate_uuid4();
        
        // Check concurrent session limit
        self::enforce_concurrent_session_limit( $user_id );

        // Create session data
        $session_data = array(
            'session_id' => $session_id,
            'user_id' => $user_id,
            'ip_address' => $ip_address,
            'user_agent' => $user_agent,
            'created_at' => current_time( 'mysql' ),
            'last_activity' => current_time( 'mysql' ),
            'expires_at' => date( 'Y-m-d H:i:s', time() + self::$session_timeout ),
            'is_active' => 1
        );

        // Store session in database
        self::store_session( $session_data );

        // Update user session metadata
        self::update_user_session_meta( $user_id, $session_id, $ip_address );

        return $session_id;
    }

    /**
     * Validate session
     *
     * @param string $session_id Session ID
     * @param int    $user_id    User ID
     * @return bool|array Session data or false if invalid
     * @since 1.0.0
     */
    public static function validate_session( $session_id, $user_id ) {
        $session = self::get_session( $session_id );

        if ( ! $session ) {
            return false;
        }

        // Check if session belongs to user
        if ( (int) $session['user_id'] !== $user_id ) {
            return false;
        }

        // Check if session is active
        if ( ! $session['is_active'] ) {
            return false;
        }

        // Check if session is expired
        if ( strtotime( $session['expires_at'] ) < time() ) {
            self::expire_session( $session_id );
            return false;
        }

        // Check for session timeout based on last activity
        $last_activity = strtotime( $session['last_activity'] );
        if ( ( time() - $last_activity ) > self::$session_timeout ) {
            self::expire_session( $session_id );
            return false;
        }

        return $session;
    }

    /**
     * Update session activity
     *
     * @param string $session_id Session ID
     * @return bool Success status
     * @since 1.0.0
     */
    public static function update_session_activity( $session_id ) {
        global $wpdb;

        $result = $wpdb->update(
            $wpdb->prefix . 'kivicare_sessions',
            array(
                'last_activity' => current_time( 'mysql' ),
                'expires_at' => date( 'Y-m-d H:i:s', time() + self::$session_timeout )
            ),
            array( 'session_id' => $session_id ),
            array( '%s', '%s' ),
            array( '%s' )
        );

        return $result !== false;
    }

    /**
     * Expire session
     *
     * @param string $session_id Session ID
     * @return bool Success status
     * @since 1.0.0
     */
    public static function expire_session( $session_id ) {
        global $wpdb;

        $result = $wpdb->update(
            $wpdb->prefix . 'kivicare_sessions',
            array(
                'is_active' => 0,
                'ended_at' => current_time( 'mysql' )
            ),
            array( 'session_id' => $session_id ),
            array( '%d', '%s' ),
            array( '%s' )
        );

        return $result !== false;
    }

    /**
     * Expire all sessions for user
     *
     * @param int $user_id User ID
     * @return bool Success status
     * @since 1.0.0
     */
    public static function expire_user_sessions( $user_id ) {
        global $wpdb;

        $result = $wpdb->update(
            $wpdb->prefix . 'kivicare_sessions',
            array(
                'is_active' => 0,
                'ended_at' => current_time( 'mysql' )
            ),
            array( 
                'user_id' => $user_id,
                'is_active' => 1
            ),
            array( '%d', '%s' ),
            array( '%d', '%d' )
        );

        // Clear user session metadata
        delete_user_meta( $user_id, 'kivicare_current_session' );
        delete_user_meta( $user_id, 'kivicare_session_ip' );

        return $result !== false;
    }

    /**
     * Get active sessions for user
     *
     * @param int $user_id User ID
     * @return array Array of active sessions
     * @since 1.0.0
     */
    public static function get_user_sessions( $user_id ) {
        global $wpdb;

        $sessions = $wpdb->get_results(
            $wpdb->prepare(
                "SELECT * FROM {$wpdb->prefix}kivicare_sessions 
                 WHERE user_id = %d AND is_active = 1 AND expires_at > NOW()
                 ORDER BY last_activity DESC",
                $user_id
            ),
            ARRAY_A
        );

        return array_map( array( self::class, 'format_session_data' ), $sessions );
    }

    /**
     * Check if user account is locked
     *
     * @param int|string $user_identifier User ID or username
     * @return bool True if account is locked
     * @since 1.0.0
     */
    public static function is_account_locked( $user_identifier ) {
        if ( is_numeric( $user_identifier ) ) {
            $user = get_user_by( 'id', $user_identifier );
        } else {
            $user = get_user_by( 'login', $user_identifier );
            if ( ! $user && is_email( $user_identifier ) ) {
                $user = get_user_by( 'email', $user_identifier );
            }
        }

        if ( ! $user ) {
            return false;
        }

        $lockout_time = get_user_meta( $user->ID, 'kivicare_lockout_time', true );
        
        if ( ! $lockout_time ) {
            return false;
        }

        // Check if lockout has expired
        if ( time() > $lockout_time ) {
            delete_user_meta( $user->ID, 'kivicare_lockout_time' );
            delete_user_meta( $user->ID, 'kivicare_failed_attempts' );
            return false;
        }

        return true;
    }

    /**
     * Get remaining lockout time
     *
     * @param int $user_id User ID
     * @return int Remaining lockout time in seconds
     * @since 1.0.0
     */
    public static function get_lockout_remaining_time( $user_id ) {
        $lockout_time = get_user_meta( $user_id, 'kivicare_lockout_time', true );
        
        if ( ! $lockout_time ) {
            return 0;
        }

        $remaining = $lockout_time - time();
        return max( 0, $remaining );
    }

    /**
     * Get session statistics for user
     *
     * @param int $user_id User ID
     * @return array Session statistics
     * @since 1.0.0
     */
    public static function get_user_session_stats( $user_id ) {
        global $wpdb;

        $stats = array(
            'active_sessions' => 0,
            'total_sessions_today' => 0,
            'total_sessions_this_month' => 0,
            'last_login' => null,
            'last_ip' => null,
            'failed_attempts_today' => 0,
            'is_locked' => false,
            'lockout_remaining' => 0
        );

        // Active sessions
        $stats['active_sessions'] = (int) $wpdb->get_var(
            $wpdb->prepare(
                "SELECT COUNT(*) FROM {$wpdb->prefix}kivicare_sessions 
                 WHERE user_id = %d AND is_active = 1 AND expires_at > NOW()",
                $user_id
            )
        );

        // Sessions today
        $stats['total_sessions_today'] = (int) $wpdb->get_var(
            $wpdb->prepare(
                "SELECT COUNT(*) FROM {$wpdb->prefix}kivicare_sessions 
                 WHERE user_id = %d AND DATE(created_at) = CURDATE()",
                $user_id
            )
        );

        // Sessions this month
        $stats['total_sessions_this_month'] = (int) $wpdb->get_var(
            $wpdb->prepare(
                "SELECT COUNT(*) FROM {$wpdb->prefix}kivicare_sessions 
                 WHERE user_id = %d AND MONTH(created_at) = MONTH(CURDATE()) AND YEAR(created_at) = YEAR(CURDATE())",
                $user_id
            )
        );

        // Last login info
        $last_session = $wpdb->get_row(
            $wpdb->prepare(
                "SELECT created_at, ip_address FROM {$wpdb->prefix}kivicare_sessions 
                 WHERE user_id = %d ORDER BY created_at DESC LIMIT 1",
                $user_id
            ),
            ARRAY_A
        );

        if ( $last_session ) {
            $stats['last_login'] = $last_session['created_at'];
            $stats['last_ip'] = $last_session['ip_address'];
        }

        // Failed attempts today
        $stats['failed_attempts_today'] = (int) $wpdb->get_var(
            $wpdb->prepare(
                "SELECT COUNT(*) FROM {$wpdb->prefix}kivicare_failed_logins 
                 WHERE user_id = %d AND DATE(attempted_at) = CURDATE()",
                $user_id
            )
        );

        // Lockout status
        $stats['is_locked'] = self::is_account_locked( $user_id );
        $stats['lockout_remaining'] = self::get_lockout_remaining_time( $user_id );

        return $stats;
    }

    /**
     * Monitor session activity for security
     *
     * @since 1.0.0
     */
    public static function monitor_session_activity() {
        // Only monitor for authenticated API requests
        if ( ! defined( 'REST_REQUEST' ) || ! REST_REQUEST ) {
            return;
        }

        $user_id = get_current_user_id();
        if ( ! $user_id ) {
            return;
        }

        // Get current session from auth header or meta
        $session_id = self::get_current_session_id( $user_id );
        
        if ( $session_id ) {
            // Update session activity
            self::update_session_activity( $session_id );
            
            // Check for suspicious activity
            self::detect_suspicious_activity( $user_id, $session_id );
        }
    }

    /**
     * Get current session ID for user
     *
     * @param int $user_id User ID
     * @return string|null Session ID or null
     * @since 1.0.0
     */
    private static function get_current_session_id( $user_id ) {
        // Try to get from JWT token first (would need to be added to JWT payload)
        // For now, get from user meta (set during authentication)
        return get_user_meta( $user_id, 'kivicare_current_session', true );
    }

    /**
     * Detect suspicious session activity
     *
     * @param int    $user_id    User ID
     * @param string $session_id Session ID
     * @since 1.0.0
     */
    private static function detect_suspicious_activity( $user_id, $session_id ) {
        $session = self::get_session( $session_id );
        if ( ! $session ) {
            return;
        }

        $current_ip = self::get_client_ip();
        $session_ip = $session['ip_address'];

        // Check for IP address change
        if ( $current_ip !== $session_ip ) {
            self::log_security_event( $user_id, 'ip_change', array(
                'session_id' => $session_id,
                'original_ip' => $session_ip,
                'new_ip' => $current_ip
            ) );

            // Optionally expire session or require re-authentication
            if ( apply_filters( 'kivicare_expire_on_ip_change', false ) ) {
                self::expire_session( $session_id );
            }
        }

        // Check for unusual activity patterns
        self::check_activity_patterns( $user_id, $session_id );
    }

    /**
     * Check for unusual activity patterns
     *
     * @param int    $user_id    User ID
     * @param string $session_id Session ID
     * @since 1.0.0
     */
    private static function check_activity_patterns( $user_id, $session_id ) {
        // This could be extended to check:
        // - Rapid API calls (possible bot activity)
        // - Access to unusual resources
        // - Concurrent sessions from different locations
        // - Time-based anomalies (access at unusual hours)

        do_action( 'kivicare_check_activity_patterns', $user_id, $session_id );
    }

    /**
     * Handle user authentication event
     *
     * @param int   $user_id User ID
     * @param array $context Authentication context
     * @since 1.0.0
     */
    public static function on_user_authenticated( $user_id, $context ) {
        $ip_address = $context['ip_address'] ?? self::get_client_ip();
        $user_agent = $context['user_agent'] ?? ( $_SERVER['HTTP_USER_AGENT'] ?? '' );

        // Create new session
        $session_id = self::create_session( $user_id, $ip_address, $user_agent );

        // Log successful authentication
        self::log_security_event( $user_id, 'login', array(
            'session_id' => $session_id,
            'ip_address' => $ip_address,
            'user_agent' => $user_agent
        ) );

        // Clear failed login attempts
        delete_user_meta( $user_id, 'kivicare_failed_attempts' );
        delete_user_meta( $user_id, 'kivicare_lockout_time' );
    }

    /**
     * Handle user logout event
     *
     * @param int $user_id User ID
     * @since 1.0.0
     */
    public static function on_user_logout( $user_id ) {
        $session_id = get_user_meta( $user_id, 'kivicare_current_session', true );

        if ( $session_id ) {
            self::expire_session( $session_id );
        }

        // Log logout
        self::log_security_event( $user_id, 'logout', array(
            'session_id' => $session_id
        ) );
    }

    /**
     * Handle failed login event
     *
     * @param array $context Failed login context
     * @since 1.0.0
     */
    public static function on_failed_login( $context ) {
        $user_id = $context['user_id'] ?? null;
        $username = $context['username'] ?? '';
        $ip_address = $context['ip_address'] ?? self::get_client_ip();

        // Log failed attempt
        self::log_failed_login_attempt( $user_id, $username, $ip_address );

        if ( $user_id ) {
            // Increment failed attempts counter
            $failed_attempts = (int) get_user_meta( $user_id, 'kivicare_failed_attempts', true ) + 1;
            update_user_meta( $user_id, 'kivicare_failed_attempts', $failed_attempts );

            // Check if account should be locked
            if ( $failed_attempts >= self::$max_failed_attempts ) {
                self::lock_account( $user_id );
            }
        }

        // Log security event
        self::log_security_event( $user_id, 'failed_login', $context );
    }

    /**
     * Lock user account
     *
     * @param int $user_id User ID
     * @since 1.0.0
     */
    private static function lock_account( $user_id ) {
        $lockout_time = time() + self::$lockout_duration;
        update_user_meta( $user_id, 'kivicare_lockout_time', $lockout_time );

        // Expire all active sessions
        self::expire_user_sessions( $user_id );

        // Log security event
        self::log_security_event( $user_id, 'account_locked', array(
            'lockout_duration' => self::$lockout_duration,
            'lockout_until' => date( 'Y-m-d H:i:s', $lockout_time )
        ) );

        // Send notification (could be extended)
        do_action( 'kivicare_account_locked', $user_id );
    }

    /**
     * Enforce concurrent session limit
     *
     * @param int $user_id User ID
     * @since 1.0.0
     */
    private static function enforce_concurrent_session_limit( $user_id ) {
        global $wpdb;

        // Get active sessions count
        $active_sessions = (int) $wpdb->get_var(
            $wpdb->prepare(
                "SELECT COUNT(*) FROM {$wpdb->prefix}kivicare_sessions 
                 WHERE user_id = %d AND is_active = 1 AND expires_at > NOW()",
                $user_id
            )
        );

        // If at limit, expire oldest session
        if ( $active_sessions >= self::$max_concurrent_sessions ) {
            $oldest_session = $wpdb->get_var(
                $wpdb->prepare(
                    "SELECT session_id FROM {$wpdb->prefix}kivicare_sessions 
                     WHERE user_id = %d AND is_active = 1 AND expires_at > NOW()
                     ORDER BY last_activity ASC LIMIT 1",
                    $user_id
                )
            );

            if ( $oldest_session ) {
                self::expire_session( $oldest_session );
            }
        }
    }

    /**
     * Store session in database
     *
     * @param array $session_data Session data
     * @return bool Success status
     * @since 1.0.0
     */
    private static function store_session( $session_data ) {
        global $wpdb;

        // Create table if it doesn't exist
        self::create_sessions_table();

        $result = $wpdb->insert(
            $wpdb->prefix . 'kivicare_sessions',
            $session_data,
            array( '%s', '%d', '%s', '%s', '%s', '%s', '%s', '%d' )
        );

        return $result !== false;
    }

    /**
     * Get session from database
     *
     * @param string $session_id Session ID
     * @return array|null Session data or null
     * @since 1.0.0
     */
    private static function get_session( $session_id ) {
        global $wpdb;

        return $wpdb->get_row(
            $wpdb->prepare(
                "SELECT * FROM {$wpdb->prefix}kivicare_sessions WHERE session_id = %s",
                $session_id
            ),
            ARRAY_A
        );
    }

    /**
     * Update user session metadata
     *
     * @param int    $user_id    User ID
     * @param string $session_id Session ID
     * @param string $ip_address IP address
     * @since 1.0.0
     */
    private static function update_user_session_meta( $user_id, $session_id, $ip_address ) {
        update_user_meta( $user_id, 'kivicare_current_session', $session_id );
        update_user_meta( $user_id, 'kivicare_session_ip', $ip_address );
        update_user_meta( $user_id, 'kivicare_last_activity', current_time( 'mysql' ) );
    }

    /**
     * Log failed login attempt
     *
     * @param int|null $user_id    User ID (if found)
     * @param string   $username   Username attempted
     * @param string   $ip_address IP address
     * @since 1.0.0
     */
    private static function log_failed_login_attempt( $user_id, $username, $ip_address ) {
        global $wpdb;

        // Create table if it doesn't exist
        self::create_failed_logins_table();

        $wpdb->insert(
            $wpdb->prefix . 'kivicare_failed_logins',
            array(
                'user_id' => $user_id,
                'username' => $username,
                'ip_address' => $ip_address,
                'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? '',
                'attempted_at' => current_time( 'mysql' )
            ),
            array( '%d', '%s', '%s', '%s', '%s' )
        );
    }

    /**
     * Log security event
     *
     * @param int    $user_id User ID
     * @param string $event   Event type
     * @param array  $data    Event data
     * @since 1.0.0
     */
    private static function log_security_event( $user_id, $event, $data = array() ) {
        global $wpdb;

        // Create table if it doesn't exist
        self::create_security_log_table();

        $wpdb->insert(
            $wpdb->prefix . 'kivicare_security_log',
            array(
                'user_id' => $user_id,
                'event_type' => $event,
                'event_data' => wp_json_encode( $data ),
                'ip_address' => self::get_client_ip(),
                'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? '',
                'created_at' => current_time( 'mysql' )
            ),
            array( '%d', '%s', '%s', '%s', '%s', '%s' )
        );
    }

    /**
     * Format session data for API response
     *
     * @param array $session_data Raw session data
     * @return array Formatted session data
     * @since 1.0.0
     */
    private static function format_session_data( $session_data ) {
        return array(
            'session_id' => $session_data['session_id'],
            'ip_address' => $session_data['ip_address'],
            'user_agent' => $session_data['user_agent'],
            'created_at' => $session_data['created_at'],
            'last_activity' => $session_data['last_activity'],
            'expires_at' => $session_data['expires_at'],
            'is_current' => get_user_meta( $session_data['user_id'], 'kivicare_current_session', true ) === $session_data['session_id']
        );
    }

    /**
     * Cleanup expired sessions
     *
     * @since 1.0.0
     */
    public static function cleanup_expired_sessions() {
        global $wpdb;

        // Delete expired sessions
        $wpdb->query(
            "DELETE FROM {$wpdb->prefix}kivicare_sessions 
             WHERE expires_at < NOW() OR (is_active = 0 AND ended_at < DATE_SUB(NOW(), INTERVAL 30 DAY))"
        );

        // Clean up old failed login attempts
        $wpdb->query(
            "DELETE FROM {$wpdb->prefix}kivicare_failed_logins 
             WHERE attempted_at < DATE_SUB(NOW(), INTERVAL 7 DAY)"
        );

        // Clean up old security log entries (keep 90 days)
        $wpdb->query(
            "DELETE FROM {$wpdb->prefix}kivicare_security_log 
             WHERE created_at < DATE_SUB(NOW(), INTERVAL 90 DAY)"
        );
    }

    /**
     * Get client IP address
     *
     * @return string IP address
     * @since 1.0.0
     */
    private static function get_client_ip() {
        $ip_keys = array(
            'HTTP_CF_CONNECTING_IP',
            'HTTP_X_FORWARDED_FOR',
            'HTTP_X_FORWARDED',
            'HTTP_X_CLUSTER_CLIENT_IP',
            'HTTP_FORWARDED_FOR',
            'HTTP_FORWARDED',
            'REMOTE_ADDR'
        );

        foreach ( $ip_keys as $key ) {
            if ( ! empty( $_SERVER[ $key ] ) ) {
                $ip = $_SERVER[ $key ];
                if ( strpos( $ip, ',' ) !== false ) {
                    $ip = explode( ',', $ip )[0];
                }
                $ip = trim( $ip );
                if ( filter_var( $ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE ) ) {
                    return $ip;
                }
            }
        }

        return $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0';
    }

    /**
     * Create sessions table
     *
     * @since 1.0.0
     */
    private static function create_sessions_table() {
        global $wpdb;

        $table_name = $wpdb->prefix . 'kivicare_sessions';
        
        $charset_collate = $wpdb->get_charset_collate();

        $sql = "CREATE TABLE IF NOT EXISTS {$table_name} (
            id bigint(20) unsigned NOT NULL AUTO_INCREMENT,
            session_id varchar(36) NOT NULL,
            user_id bigint(20) unsigned NOT NULL,
            ip_address varchar(45) NOT NULL,
            user_agent text NOT NULL,
            created_at datetime NOT NULL,
            last_activity datetime NOT NULL,
            expires_at datetime NOT NULL,
            ended_at datetime NULL,
            is_active tinyint(1) NOT NULL DEFAULT 1,
            PRIMARY KEY (id),
            UNIQUE KEY session_id (session_id),
            KEY user_id (user_id),
            KEY expires_at (expires_at),
            KEY is_active (is_active)
        ) {$charset_collate};";

        require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
        dbDelta( $sql );
    }

    /**
     * Create failed logins table
     *
     * @since 1.0.0
     */
    private static function create_failed_logins_table() {
        global $wpdb;

        $table_name = $wpdb->prefix . 'kivicare_failed_logins';
        
        $charset_collate = $wpdb->get_charset_collate();

        $sql = "CREATE TABLE IF NOT EXISTS {$table_name} (
            id bigint(20) unsigned NOT NULL AUTO_INCREMENT,
            user_id bigint(20) unsigned NULL,
            username varchar(60) NOT NULL,
            ip_address varchar(45) NOT NULL,
            user_agent text NOT NULL,
            attempted_at datetime NOT NULL,
            PRIMARY KEY (id),
            KEY user_id (user_id),
            KEY ip_address (ip_address),
            KEY attempted_at (attempted_at)
        ) {$charset_collate};";

        require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
        dbDelta( $sql );
    }

    /**
     * Create security log table
     *
     * @since 1.0.0
     */
    private static function create_security_log_table() {
        global $wpdb;

        $table_name = $wpdb->prefix . 'kivicare_security_log';
        
        $charset_collate = $wpdb->get_charset_collate();

        $sql = "CREATE TABLE IF NOT EXISTS {$table_name} (
            id bigint(20) unsigned NOT NULL AUTO_INCREMENT,
            user_id bigint(20) unsigned NULL,
            event_type varchar(50) NOT NULL,
            event_data longtext NULL,
            ip_address varchar(45) NOT NULL,
            user_agent text NOT NULL,
            created_at datetime NOT NULL,
            PRIMARY KEY (id),
            KEY user_id (user_id),
            KEY event_type (event_type),
            KEY created_at (created_at)
        ) {$charset_collate};";

        require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
        dbDelta( $sql );
    }
}