<?php
/**
 * Performance Monitoring Service
 *
 * Monitors API performance, tracks metrics, and provides optimization insights
 *
 * @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;

use Care_API\Utils\API_Logger;

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

/**
 * Class Performance_Monitoring_Service
 *
 * Comprehensive performance monitoring and optimization
 *
 * @since 1.0.0
 */
class Performance_Monitoring_Service {

    /**
     * Performance thresholds
     *
     * @var array
     */
    private static $thresholds = array(
        'response_time_warning' => 1000,  // 1 second
        'response_time_critical' => 3000, // 3 seconds
        'memory_usage_warning' => 50,     // 50MB
        'memory_usage_critical' => 100,   // 100MB
        'query_time_warning' => 100,      // 100ms
        'query_time_critical' => 500,     // 500ms
        'slow_query_threshold' => 50      // 50ms
    );

    /**
     * Metrics storage
     *
     * @var array
     */
    private static $metrics = array();

    /**
     * Request start time
     *
     * @var float
     */
    private static $request_start_time;

    /**
     * Memory usage at start
     *
     * @var int
     */
    private static $initial_memory_usage;

    /**
     * Database query count at start
     *
     * @var int
     */
    private static $initial_query_count;

    /**
     * Initialize performance monitoring
     *
     * @since 1.0.0
     */
    public static function init() {
        // Hook into WordPress lifecycle
        add_action( 'init', array( __CLASS__, 'start_monitoring' ), 1 );
        add_action( 'shutdown', array( __CLASS__, 'end_monitoring' ), 999 );
        
        // Monitor database queries
        add_filter( 'query', array( __CLASS__, 'monitor_query' ), 10, 1 );
        
        // Monitor REST API requests
        add_filter( 'rest_pre_dispatch', array( __CLASS__, 'start_api_monitoring' ), 10, 3 );
        add_filter( 'rest_post_dispatch', array( __CLASS__, 'end_api_monitoring' ), 10, 3 );
        
        // Schedule performance reports
        if ( ! wp_next_scheduled( 'kivicare_performance_report' ) ) {
            wp_schedule_event( time(), 'daily', 'kivicare_performance_report' );
        }
        add_action( 'kivicare_performance_report', array( __CLASS__, 'generate_daily_report' ) );
        
        // Memory limit monitoring
        add_action( 'wp_loaded', array( __CLASS__, 'check_memory_usage' ) );
    }

    /**
     * Start monitoring for current request
     *
     * @since 1.0.0
     */
    public static function start_monitoring() {
        self::$request_start_time = microtime( true );
        self::$initial_memory_usage = memory_get_usage( true );
        self::$initial_query_count = get_num_queries();
        
        // Initialize metrics for this request
        self::$metrics = array(
            'queries' => array(),
            'slow_queries' => array(),
            'api_calls' => array(),
            'cache_hits' => 0,
            'cache_misses' => 0
        );
    }

    /**
     * End monitoring and log metrics
     *
     * @since 1.0.0
     */
    public static function end_monitoring() {
        if ( ! self::$request_start_time ) {
            return;
        }

        $total_time = ( microtime( true ) - self::$request_start_time ) * 1000; // Convert to milliseconds
        $memory_usage = memory_get_usage( true ) - self::$initial_memory_usage;
        $peak_memory = memory_get_peak_usage( true );
        $query_count = get_num_queries() - self::$initial_query_count;

        $metrics = array(
            'timestamp' => current_time( 'Y-m-d H:i:s' ),
            'request_uri' => $_SERVER['REQUEST_URI'] ?? '',
            'request_method' => $_SERVER['REQUEST_METHOD'] ?? '',
            'response_time_ms' => round( $total_time, 2 ),
            'memory_usage_bytes' => $memory_usage,
            'peak_memory_bytes' => $peak_memory,
            'query_count' => $query_count,
            'slow_query_count' => count( self::$metrics['slow_queries'] ),
            'cache_hits' => self::$metrics['cache_hits'],
            'cache_misses' => self::$metrics['cache_misses'],
            'user_id' => get_current_user_id(),
            'is_api_request' => self::is_api_request(),
            'php_version' => PHP_VERSION,
            'wordpress_version' => get_bloginfo( 'version' )
        );

        // Check thresholds and log warnings
        self::check_performance_thresholds( $metrics );
        
        // Store metrics
        self::store_metrics( $metrics );
        
        // Log detailed metrics for slow requests
        if ( $total_time > self::$thresholds['response_time_warning'] ) {
            $metrics['slow_queries'] = self::$metrics['slow_queries'];
            API_Logger::log_performance_issue( null, $total_time );
        }
    }

    /**
     * Monitor database queries
     *
     * @param string $query SQL query
     * @return string Original query
     * @since 1.0.0
     */
    public static function monitor_query( $query ) {
        static $query_start_time = null;
        static $current_query = null;
        
        // Start timing if this is a new query
        if ( $query !== $current_query ) {
            // Log previous query if it exists
            if ( $current_query && $query_start_time ) {
                self::log_query_performance( $current_query, $query_start_time );
            }
            
            $current_query = $query;
            $query_start_time = microtime( true );
        }
        
        return $query;
    }

    /**
     * Log query performance
     *
     * @param string $query      SQL query
     * @param float  $start_time Query start time
     * @since 1.0.0
     */
    private static function log_query_performance( $query, $start_time ) {
        $execution_time = ( microtime( true ) - $start_time ) * 1000; // Convert to milliseconds
        
        $query_info = array(
            'query' => $query,
            'execution_time_ms' => round( $execution_time, 2 ),
            'timestamp' => current_time( 'Y-m-d H:i:s' )
        );
        
        self::$metrics['queries'][] = $query_info;
        
        // Log slow queries
        if ( $execution_time > self::$thresholds['slow_query_threshold'] ) {
            self::$metrics['slow_queries'][] = $query_info;
            
            API_Logger::log_database_operation( 
                'slow_query',
                self::extract_table_name( $query ),
                $execution_time,
                0,
                $execution_time > self::$thresholds['query_time_critical'] ? 'Critical slow query' : ''
            );
        }
    }

    /**
     * Start API request monitoring
     *
     * @param mixed           $result  Response to replace the requested version with
     * @param WP_REST_Server  $server  Server instance
     * @param WP_REST_Request $request Request object
     * @return mixed
     * @since 1.0.0
     */
    public static function start_api_monitoring( $result, $server, $request ) {
        // Only monitor Care API requests
        $route = $request->get_route();
        if ( strpos( $route, '/care/v1/' ) === false ) {
            return $result;
        }

        $GLOBALS['care_api_start_time'] = microtime( true );
        $GLOBALS['care_api_start_memory'] = memory_get_usage( true );
        $GLOBALS['care_api_start_queries'] = get_num_queries();

        return $result;
    }

    /**
     * End API request monitoring
     *
     * @param WP_REST_Response $result  Response object
     * @param WP_REST_Server   $server  Server instance
     * @param WP_REST_Request  $request Request object
     * @return WP_REST_Response
     * @since 1.0.0
     */
    public static function end_api_monitoring( $result, $server, $request ) {
        // Only monitor Care API requests
        $route = $request->get_route();
        if ( strpos( $route, '/care/v1/' ) === false ) {
            return $result;
        }

        if ( ! isset( $GLOBALS['care_api_start_time'] ) ) {
            return $result;
        }

        $execution_time = ( microtime( true ) - $GLOBALS['care_api_start_time'] ) * 1000;
        $memory_usage = memory_get_usage( true ) - $GLOBALS['care_api_start_memory'];
        $query_count = get_num_queries() - $GLOBALS['care_api_start_queries'];

        $api_metrics = array(
            'route' => $route,
            'method' => $request->get_method(),
            'execution_time_ms' => round( $execution_time, 2 ),
            'memory_usage_bytes' => $memory_usage,
            'query_count' => $query_count,
            'status_code' => $result->get_status(),
            'response_size_bytes' => strlen( json_encode( $result->get_data() ) ),
            'user_id' => get_current_user_id(),
            'timestamp' => current_time( 'Y-m-d H:i:s' )
        );

        self::$metrics['api_calls'][] = $api_metrics;

        // Log performance data
        API_Logger::log_api_response( $request, $result, $execution_time );

        // Add performance headers to response
        if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
            $result->header( 'X-Response-Time', $execution_time . 'ms' );
            $result->header( 'X-Memory-Usage', self::format_bytes( $memory_usage ) );
            $result->header( 'X-Query-Count', $query_count );
        }

        // Clean up globals
        unset( $GLOBALS['care_api_start_time'] );
        unset( $GLOBALS['care_api_start_memory'] );
        unset( $GLOBALS['care_api_start_queries'] );

        return $result;
    }

    /**
     * Check performance thresholds
     *
     * @param array $metrics Performance metrics
     * @since 1.0.0
     */
    private static function check_performance_thresholds( $metrics ) {
        $alerts = array();

        // Check response time
        if ( $metrics['response_time_ms'] > self::$thresholds['response_time_critical'] ) {
            $alerts[] = array(
                'type' => 'critical',
                'metric' => 'response_time',
                'value' => $metrics['response_time_ms'],
                'threshold' => self::$thresholds['response_time_critical'],
                'message' => 'Critical response time detected'
            );
        } elseif ( $metrics['response_time_ms'] > self::$thresholds['response_time_warning'] ) {
            $alerts[] = array(
                'type' => 'warning',
                'metric' => 'response_time',
                'value' => $metrics['response_time_ms'],
                'threshold' => self::$thresholds['response_time_warning'],
                'message' => 'Slow response time detected'
            );
        }

        // Check memory usage
        $memory_mb = $metrics['memory_usage_bytes'] / 1024 / 1024;
        if ( $memory_mb > self::$thresholds['memory_usage_critical'] ) {
            $alerts[] = array(
                'type' => 'critical',
                'metric' => 'memory_usage',
                'value' => $memory_mb,
                'threshold' => self::$thresholds['memory_usage_critical'],
                'message' => 'Critical memory usage detected'
            );
        } elseif ( $memory_mb > self::$thresholds['memory_usage_warning'] ) {
            $alerts[] = array(
                'type' => 'warning',
                'metric' => 'memory_usage',
                'value' => $memory_mb,
                'threshold' => self::$thresholds['memory_usage_warning'],
                'message' => 'High memory usage detected'
            );
        }

        // Check slow queries
        if ( $metrics['slow_query_count'] > 5 ) {
            $alerts[] = array(
                'type' => 'warning',
                'metric' => 'slow_queries',
                'value' => $metrics['slow_query_count'],
                'threshold' => 5,
                'message' => 'Multiple slow queries detected'
            );
        }

        // Log alerts
        foreach ( $alerts as $alert ) {
            $log_level = $alert['type'] === 'critical' ? 'critical_event' : 'business_event';
            
            if ( $log_level === 'critical_event' ) {
                API_Logger::log_critical_event( 
                    'performance_threshold_exceeded',
                    $alert['message'],
                    array_merge( $alert, $metrics )
                );
            } else {
                API_Logger::log_business_event( 
                    'performance_warning',
                    $alert['message'],
                    $alert
                );
            }
        }
    }

    /**
     * Store performance metrics
     *
     * @param array $metrics Performance metrics
     * @since 1.0.0
     */
    private static function store_metrics( $metrics ) {
        // Store in WordPress transient for recent access
        $recent_metrics = get_transient( 'kivicare_recent_performance_metrics' );
        if ( ! is_array( $recent_metrics ) ) {
            $recent_metrics = array();
        }

        $recent_metrics[] = $metrics;
        
        // Keep only last 100 metrics
        if ( count( $recent_metrics ) > 100 ) {
            $recent_metrics = array_slice( $recent_metrics, -100 );
        }

        set_transient( 'kivicare_recent_performance_metrics', $recent_metrics, HOUR_IN_SECONDS );

        // Store daily aggregated metrics
        self::update_daily_aggregates( $metrics );
    }

    /**
     * Update daily performance aggregates
     *
     * @param array $metrics Performance metrics
     * @since 1.0.0
     */
    private static function update_daily_aggregates( $metrics ) {
        $today = date( 'Y-m-d' );
        $daily_key = "kivicare_daily_performance_{$today}";
        
        $daily_metrics = get_option( $daily_key, array(
            'date' => $today,
            'request_count' => 0,
            'total_response_time' => 0,
            'max_response_time' => 0,
            'total_memory_usage' => 0,
            'max_memory_usage' => 0,
            'total_queries' => 0,
            'max_queries' => 0,
            'slow_request_count' => 0,
            'api_request_count' => 0,
            'error_count' => 0
        ) );

        // Update aggregates
        $daily_metrics['request_count']++;
        $daily_metrics['total_response_time'] += $metrics['response_time_ms'];
        $daily_metrics['max_response_time'] = max( $daily_metrics['max_response_time'], $metrics['response_time_ms'] );
        $daily_metrics['total_memory_usage'] += $metrics['memory_usage_bytes'];
        $daily_metrics['max_memory_usage'] = max( $daily_metrics['max_memory_usage'], $metrics['memory_usage_bytes'] );
        $daily_metrics['total_queries'] += $metrics['query_count'];
        $daily_metrics['max_queries'] = max( $daily_metrics['max_queries'], $metrics['query_count'] );

        if ( $metrics['response_time_ms'] > self::$thresholds['response_time_warning'] ) {
            $daily_metrics['slow_request_count']++;
        }

        if ( $metrics['is_api_request'] ) {
            $daily_metrics['api_request_count']++;
        }

        update_option( $daily_key, $daily_metrics );
    }

    /**
     * Get performance statistics
     *
     * @param int $days Number of days to analyze
     * @return array Performance statistics
     * @since 1.0.0
     */
    public static function get_performance_statistics( $days = 7 ) {
        $stats = array(
            'period' => $days,
            'daily_stats' => array(),
            'summary' => array(),
            'trends' => array(),
            'recommendations' => array()
        );

        $total_requests = 0;
        $total_response_time = 0;
        $total_slow_requests = 0;
        $total_api_requests = 0;

        // Collect daily statistics
        for ( $i = 0; $i < $days; $i++ ) {
            $date = date( 'Y-m-d', strtotime( "-{$i} days" ) );
            $daily_key = "kivicare_daily_performance_{$date}";
            $daily_data = get_option( $daily_key, null );

            if ( $daily_data ) {
                $daily_data['average_response_time'] = $daily_data['request_count'] > 0 
                    ? $daily_data['total_response_time'] / $daily_data['request_count'] 
                    : 0;
                
                $stats['daily_stats'][$date] = $daily_data;

                $total_requests += $daily_data['request_count'];
                $total_response_time += $daily_data['total_response_time'];
                $total_slow_requests += $daily_data['slow_request_count'];
                $total_api_requests += $daily_data['api_request_count'];
            }
        }

        // Calculate summary statistics
        $stats['summary'] = array(
            'total_requests' => $total_requests,
            'average_response_time' => $total_requests > 0 ? $total_response_time / $total_requests : 0,
            'slow_request_percentage' => $total_requests > 0 ? ( $total_slow_requests / $total_requests ) * 100 : 0,
            'api_request_percentage' => $total_requests > 0 ? ( $total_api_requests / $total_requests ) * 100 : 0
        );

        // Generate recommendations
        $stats['recommendations'] = self::generate_performance_recommendations( $stats );

        return $stats;
    }

    /**
     * Generate performance recommendations
     *
     * @param array $stats Performance statistics
     * @return array Recommendations
     * @since 1.0.0
     */
    private static function generate_performance_recommendations( $stats ) {
        $recommendations = array();

        // Check average response time
        if ( $stats['summary']['average_response_time'] > self::$thresholds['response_time_warning'] ) {
            $recommendations[] = array(
                'type' => 'performance',
                'priority' => 'high',
                'title' => 'High Average Response Time',
                'description' => 'Average response time is ' . round( $stats['summary']['average_response_time'], 2 ) . 'ms',
                'action' => 'Consider implementing caching, optimizing database queries, or upgrading server resources'
            );
        }

        // Check slow request percentage
        if ( $stats['summary']['slow_request_percentage'] > 20 ) {
            $recommendations[] = array(
                'type' => 'optimization',
                'priority' => 'medium',
                'title' => 'High Percentage of Slow Requests',
                'description' => round( $stats['summary']['slow_request_percentage'], 2 ) . '% of requests are slow',
                'action' => 'Review slow queries, implement query optimization, and consider adding database indexes'
            );
        }

        // Check recent trends
        $recent_days = array_slice( $stats['daily_stats'], 0, 3, true );
        $response_times = array_column( $recent_days, 'average_response_time' );
        
        if ( count( $response_times ) >= 2 ) {
            $trend = end( $response_times ) - reset( $response_times );
            if ( $trend > 100 ) { // Response time increasing by more than 100ms
                $recommendations[] = array(
                    'type' => 'trend',
                    'priority' => 'medium',
                    'title' => 'Performance Degradation Trend',
                    'description' => 'Response times have been increasing over the last few days',
                    'action' => 'Monitor system resources and investigate potential bottlenecks'
                );
            }
        }

        return $recommendations;
    }

    /**
     * Generate daily performance report
     *
     * @since 1.0.0
     */
    public static function generate_daily_report() {
        $yesterday = date( 'Y-m-d', strtotime( '-1 day' ) );
        $daily_key = "kivicare_daily_performance_{$yesterday}";
        $daily_metrics = get_option( $daily_key );

        if ( ! $daily_metrics ) {
            return;
        }

        $report = array(
            'date' => $yesterday,
            'metrics' => $daily_metrics,
            'performance_grade' => self::calculate_performance_grade( $daily_metrics ),
            'recommendations' => array()
        );

        // Calculate averages
        if ( $daily_metrics['request_count'] > 0 ) {
            $report['metrics']['average_response_time'] = $daily_metrics['total_response_time'] / $daily_metrics['request_count'];
            $report['metrics']['average_memory_usage'] = $daily_metrics['total_memory_usage'] / $daily_metrics['request_count'];
            $report['metrics']['average_queries'] = $daily_metrics['total_queries'] / $daily_metrics['request_count'];
        }

        // Log the daily report
        API_Logger::log_business_event( 
            'daily_performance_report',
            "Daily performance report for {$yesterday}",
            $report
        );

        // Store the report
        update_option( "kivicare_performance_report_{$yesterday}", $report );

        // Send email notification if performance is poor
        if ( $report['performance_grade'] === 'D' || $report['performance_grade'] === 'F' ) {
            self::send_performance_alert( $report );
        }
    }

    /**
     * Calculate performance grade
     *
     * @param array $metrics Daily metrics
     * @return string Performance grade (A-F)
     * @since 1.0.0
     */
    private static function calculate_performance_grade( $metrics ) {
        $score = 100;

        if ( $metrics['request_count'] > 0 ) {
            $avg_response_time = $metrics['total_response_time'] / $metrics['request_count'];
            
            // Deduct points for slow response time
            if ( $avg_response_time > self::$thresholds['response_time_critical'] ) {
                $score -= 40;
            } elseif ( $avg_response_time > self::$thresholds['response_time_warning'] ) {
                $score -= 20;
            }

            // Deduct points for slow requests percentage
            $slow_percentage = ( $metrics['slow_request_count'] / $metrics['request_count'] ) * 100;
            if ( $slow_percentage > 30 ) {
                $score -= 30;
            } elseif ( $slow_percentage > 15 ) {
                $score -= 15;
            }

            // Deduct points for high query count
            $avg_queries = $metrics['total_queries'] / $metrics['request_count'];
            if ( $avg_queries > 20 ) {
                $score -= 20;
            } elseif ( $avg_queries > 10 ) {
                $score -= 10;
            }
        }

        // Convert score to grade
        if ( $score >= 90 ) return 'A';
        if ( $score >= 80 ) return 'B';
        if ( $score >= 70 ) return 'C';
        if ( $score >= 60 ) return 'D';
        return 'F';
    }

    /**
     * Send performance alert email
     *
     * @param array $report Performance report
     * @since 1.0.0
     */
    private static function send_performance_alert( $report ) {
        $admin_email = get_option( 'admin_email' );
        if ( ! $admin_email ) {
            return;
        }

        $subject = '[Care API] Performance Alert - Grade ' . $report['performance_grade'];
        $message = "Performance report for {$report['date']}:\n\n";
        $message .= "Grade: {$report['performance_grade']}\n";
        $message .= "Total Requests: {$report['metrics']['request_count']}\n";
        $message .= "Average Response Time: " . round( $report['metrics']['average_response_time'] ?? 0, 2 ) . "ms\n";
        $message .= "Slow Requests: {$report['metrics']['slow_request_count']}\n";
        $message .= "Max Response Time: {$report['metrics']['max_response_time']}ms\n";
        $message .= "Max Memory Usage: " . self::format_bytes( $report['metrics']['max_memory_usage'] ) . "\n\n";
        $message .= "Please review the system performance and consider optimization measures.";

        wp_mail( $admin_email, $subject, $message );
    }

    /**
     * Check current memory usage
     *
     * @since 1.0.0
     */
    public static function check_memory_usage() {
        $memory_usage = memory_get_usage( true );
        $memory_limit = self::get_memory_limit_bytes();
        
        if ( $memory_limit > 0 ) {
            $usage_percentage = ( $memory_usage / $memory_limit ) * 100;
            
            if ( $usage_percentage > 80 ) {
                API_Logger::log_critical_event( 
                    'high_memory_usage',
                    'Memory usage is ' . round( $usage_percentage, 2 ) . '% of limit',
                    array(
                        'current_usage' => $memory_usage,
                        'memory_limit' => $memory_limit,
                        'usage_percentage' => $usage_percentage
                    )
                );
            }
        }
    }

    /**
     * Utility methods
     */

    /**
     * Check if current request is an API request
     *
     * @return bool True if API request
     * @since 1.0.0
     */
    private static function is_api_request() {
        return isset( $_SERVER['REQUEST_URI'] ) && strpos( $_SERVER['REQUEST_URI'], '/wp-json/care/v1/' ) !== false;
    }

    /**
     * Extract table name from SQL query
     *
     * @param string $query SQL query
     * @return string Table name
     * @since 1.0.0
     */
    private static function extract_table_name( $query ) {
        // Simple extraction - could be improved with more sophisticated parsing
        if ( preg_match( '/FROM\s+(\w+)/i', $query, $matches ) ) {
            return $matches[1];
        }
        if ( preg_match( '/UPDATE\s+(\w+)/i', $query, $matches ) ) {
            return $matches[1];
        }
        if ( preg_match( '/INSERT\s+INTO\s+(\w+)/i', $query, $matches ) ) {
            return $matches[1];
        }
        return 'unknown';
    }

    /**
     * Format bytes to human readable format
     *
     * @param int $bytes Bytes
     * @return string Formatted string
     * @since 1.0.0
     */
    private static function format_bytes( $bytes ) {
        $units = array( 'B', 'KB', 'MB', 'GB' );
        $bytes = max( $bytes, 0 );
        $pow = floor( ( $bytes ? log( $bytes ) : 0 ) / log( 1024 ) );
        $pow = min( $pow, count( $units ) - 1 );
        
        $bytes /= pow( 1024, $pow );
        
        return round( $bytes, 2 ) . ' ' . $units[$pow];
    }

    /**
     * Get memory limit in bytes
     *
     * @return int Memory limit in bytes
     * @since 1.0.0
     */
    private static function get_memory_limit_bytes() {
        $memory_limit = ini_get( 'memory_limit' );
        
        if ( ! $memory_limit || $memory_limit === '-1' ) {
            return 0;
        }
        
        $unit = strtolower( substr( $memory_limit, -1 ) );
        $value = (int) substr( $memory_limit, 0, -1 );
        
        switch ( $unit ) {
            case 'g':
                $value *= 1024;
            case 'm':
                $value *= 1024;
            case 'k':
                $value *= 1024;
        }
        
        return $value;
    }

    /**
     * Get real-time performance metrics
     *
     * @return array Real-time metrics
     * @since 1.0.0
     */
    public static function get_realtime_metrics() {
        return array(
            'memory_usage' => memory_get_usage( true ),
            'memory_peak' => memory_get_peak_usage( true ),
            'memory_limit' => self::get_memory_limit_bytes(),
            'uptime' => time() - (int) get_option( 'care_api_start_time', time() ),
            'php_version' => PHP_VERSION,
            'mysql_version' => $GLOBALS['wpdb']->get_var( 'SELECT VERSION()' ),
            'wordpress_version' => get_bloginfo( 'version' ),
            'cache_stats' => Cache_Service::get_statistics()
        );
    }
}