<?php
/**
 * Total Processing Gateway Logger - Core Class
 * 
 * Handles all database operations for gateway logging
 *
 * @package TotalProcessing
 * @subpackage Gateway_Logger
 */

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

class TP_Gateway_Logger {
    
    /**
     * Log levels
     */
    const LEVEL_ERROR = 'error';
    const LEVEL_WARNING = 'warning';
    const LEVEL_INFO = 'info';
    const LEVEL_SUCCESS = 'success';
    
    /**
     * Insert a log entry
     *
     * @param string $gateway_id Gateway identifier
     * @param string $level Log level
     * @param string $message Log message
     * @param array $data Additional data
     * @param int|null $order_id Order ID
     * @param string|null $transaction_id Transaction ID
     * @param string|null $checkout_id Checkout ID
     * @return int|false Log ID or false on failure
     */
    public static function log($gateway_id, $level, $message, $data = [], $order_id = null, $transaction_id = null, $checkout_id = null) {
        global $wpdb;
        
        // Check if logging is enabled for this gateway
        if (!self::is_logging_enabled($gateway_id)) {
            return false;
        }
        
        // Ensure table exists
        if (!TP_Gateway_Logger_Table::table_exists()) {
            TP_Gateway_Logger_Table::create_table();
        }
        
        $table_name = TP_Gateway_Logger_Table::get_table_name();
        
        // Prepare log entry
        $log_entry = [
            'gateway_id' => sanitize_text_field($gateway_id),
            'log_level' => sanitize_text_field($level),
            'message' => sanitize_textarea_field($message),
            'log_data' => !empty($data) ? wp_json_encode($data) : null,
            'order_id' => $order_id ? absint($order_id) : null,
            'transaction_id' => $transaction_id ? sanitize_text_field($transaction_id) : null,
            'checkout_id' => $checkout_id ? sanitize_text_field($checkout_id) : null,
            'user_id' => get_current_user_id() ?: null,
            'session_id' => WC()->session ? WC()->session->get_customer_id() : null,
            'ip_address' => self::get_client_ip(),
            'cart_hash' => WC()->cart ? WC()->cart->get_cart_hash() : null,
            'request_url' => self::get_current_url(),
            'stack_trace' => ($level === self::LEVEL_ERROR) ? self::get_stack_trace() : null,
            'created_at' => current_time('mysql')
        ];
        
        $result = $wpdb->insert($table_name, $log_entry);
        
        if ($result === false) {
            error_log('TP Gateway Logger: Failed to insert log - ' . $wpdb->last_error);
            return false;
        }
        
        return $wpdb->insert_id;
    }
    
    /**
     * Get logs with filters
     * Uses OR logic for order_id, checkout_id, transaction_id
     * Uses AND logic for gateway_id, log_level
     *
     * @param array $args Query arguments
     * @return array|object|null
     */
    public static function get_logs($args = []) {
        global $wpdb;
        $table_name = TP_Gateway_Logger_Table::get_table_name();
        
        if (!TP_Gateway_Logger_Table::table_exists()) {
            return [];
        }
        
        $defaults = [
            'gateway_id' => '',
            'order_id' => null,
            'checkout_id' => '',
            'transaction_id' => '',
            'log_level' => '',
            'limit' => 20,
            'offset' => 0,
            'orderby' => 'id',
            'order' => 'ASC'
        ];
        
        $args = wp_parse_args($args, $defaults);
        
        // Build WHERE clause
        $where = [];
        $values = [];
        
        // AND conditions (must match)
        if (!empty($args['gateway_id'])) {
            $where[] = 'gateway_id = %s';
            $values[] = $args['gateway_id'];
        }
        
        if (!empty($args['log_level'])) {
            $where[] = 'log_level = %s';
            $values[] = $args['log_level'];
        }
        
        // OR conditions for identifiers (match any)
        $or_conditions = [];
        
        if (!empty($args['order_id'])) {
            $or_conditions[] = 'order_id = %d';
            $values[] = absint($args['order_id']);
        }
        
        if (!empty($args['transaction_id'])) {
            $or_conditions[] = 'transaction_id = %s';
            $values[] = $args['transaction_id'];
        }
        
        if (!empty($args['checkout_id'])) {
            $or_conditions[] = 'checkout_id = %s';
            $values[] = $args['checkout_id'];
        }
        
        // Combine OR conditions with parentheses
        if (!empty($or_conditions)) {
            $where[] = '(' . implode(' OR ', $or_conditions) . ')';
        }
        
        // Build final WHERE clause
        $where_clause = !empty($where) ? implode(' AND ', $where) : '1=1';
        
        // Build ORDER BY clause
        $orderby = sanitize_sql_orderby($args['orderby'] . ' ' . $args['order']);
        if (!$orderby) {
            $orderby = 'id ASC';
        }
        
        // Build query
        $query = "SELECT * FROM {$table_name} WHERE {$where_clause} ORDER BY {$orderby}";
        
        // Add pagination
        if ($args['limit'] > 0) {
            $query .= $wpdb->prepare(" LIMIT %d OFFSET %d", absint($args['limit']), absint($args['offset']));
        }
        
        // Prepare query with values
        if (!empty($values)) {
            $query = $wpdb->prepare($query, $values);
        }
        
        return $wpdb->get_results($query);
    }

    /**
     * Get total count of logs
     *
     * @param array $args Query arguments
     * @return int
     */
    public static function get_logs_count($args = []) {
        global $wpdb;
        $table_name = TP_Gateway_Logger_Table::get_table_name();
        
        if (!TP_Gateway_Logger_Table::table_exists()) {
            return 0;
        }
        
        // Build WHERE clause
        $where = ['1=1'];
        $values = [];
        
        if (!empty($args['gateway_id'])) {
            $where[] = 'gateway_id = %s';
            $values[] = $args['gateway_id'];
        }
        
        if (!empty($args['order_id'])) {
            $where[] = 'order_id = %d';
            $values[] = absint($args['order_id']);
        }
        
        if (!empty($args['log_level'])) {
            $where[] = 'log_level = %s';
            $values[] = $args['log_level'];
        }
        
        $where_clause = implode(' AND ', $where);
        $query = "SELECT COUNT(*) FROM {$table_name} WHERE {$where_clause}";
        
        if (!empty($values)) {
            $query = $wpdb->prepare($query, $values);
        }
        
        return (int) $wpdb->get_var($query);
    }
    
    /**
     * Delete logs for a specific order
     *
     * @param int $order_id
     * @return int|false Number of rows deleted or false on failure
     */
    public static function delete_order_logs($order_id) {
        global $wpdb;
        $table_name = TP_Gateway_Logger_Table::get_table_name();
        
        if (!TP_Gateway_Logger_Table::table_exists()) {
            return false;
        }
        
        return $wpdb->delete($table_name, ['order_id' => absint($order_id)], ['%d']);
    }
    
    /**
     * Delete logs for a specific gateway
     *
     * @param string $gateway_id
     * @return int|false Number of rows deleted or false on failure
     */
    public static function delete_gateway_logs($gateway_id) {
        global $wpdb;
        $table_name = TP_Gateway_Logger_Table::get_table_name();
        
        if (!TP_Gateway_Logger_Table::table_exists()) {
            return false;
        }
        
        return $wpdb->delete($table_name, ['gateway_id' => sanitize_text_field($gateway_id)], ['%s']);
    }
    
    /**
     * Delete old logs based on retention period
     *
     * @param string $gateway_id
     * @param int $retention_days
     * @return int|false Number of rows deleted or false on failure
     */
    public static function cleanup_old_logs($gateway_id, $retention_days) {
        global $wpdb;
        $table_name = TP_Gateway_Logger_Table::get_table_name();
        
        if (!TP_Gateway_Logger_Table::table_exists() || $retention_days <= 0) {
            return false;
        }
        
        $cutoff_date = date('Y-m-d H:i:s', strtotime("-{$retention_days} days"));
        
        return $wpdb->query($wpdb->prepare(
            "DELETE FROM {$table_name} WHERE gateway_id = %s AND created_at < %s",
            $gateway_id,
            $cutoff_date
        ));
    }
    
    /**
     * Check if logging is enabled for gateway
     *
     * @param string $gateway_id
     * @return bool
     */
    private static function is_logging_enabled($gateway_id) {
        $settings = get_option('woocommerce_' . $gateway_id . '_settings', []);
        return isset($settings['gateway_logging_enabled']) && $settings['gateway_logging_enabled'] === 'yes';
    }
    
    /**
     * Get client IP address
     *
     * @return string
     */
    private static function get_client_ip() {
        $ip_keys = ['HTTP_X_FORWARDED_FOR', 'HTTP_X_REAL_IP', 'HTTP_CLIENT_IP', 'REMOTE_ADDR'];
        
        foreach ($ip_keys as $key) {
            if (!empty($_SERVER[$key])) {
                $ip = $_SERVER[$key];
                if (strpos($ip, ',') !== false) {
                    $ip = trim(explode(',', $ip)[0]);
                }
                if (filter_var($ip, FILTER_VALIDATE_IP)) {
                    return $ip;
                }
            }
        }
        
        return $_SERVER['REMOTE_ADDR'] ?? 'unknown';
    }
    
    /**
     * Get current request URL
     *
     * @return string
     */
    private static function get_current_url() {
        $url = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? 'https' : 'http') . '://';
        $url .= $_SERVER['HTTP_HOST'] ?? '';
        $url .= $_SERVER['REQUEST_URI'] ?? '';
        
        // Truncate if too long
        return substr($url, 0, 255);
    }
    
    /**
     * Get stack trace (for errors only)
     *
     * @return string|null
     */
    private static function get_stack_trace() {
        $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 10);
        $formatted_trace = [];
        
        foreach ($trace as $index => $frame) {
            if (isset($frame['file'])) {
                $formatted_trace[] = sprintf(
                    '#%d %s(%d)',
                    $index,
                    str_replace(ABSPATH, '', $frame['file']),
                    $frame['line'] ?? 0
                );
            }
        }
        
        return !empty($formatted_trace) ? implode("\n", $formatted_trace) : null;
    }
}
