<?php

declare(strict_types=1);

namespace App\Framework\Mcp\Tools\Categories\Performance;

use App\Framework\Cache\Cache;
use App\Framework\Mcp\Core\Services\McpToolContext;
use App\Framework\Mcp\Core\ValueObjects\OutputFormat;
use App\Framework\Mcp\McpTool;

final readonly class CacheTools
{
    public function __construct(
        private ?Cache $cache,
        private McpToolContext $context
    ) {
    }

    #[McpTool(
        name: 'cache_health_check',
        description: 'Check cache system health and connectivity with comprehensive diagnostics',
        category: 'performance',
        tags: ['cache', 'health', 'connectivity'],
        cacheable: false
    )]
    public function cacheHealthCheck(OutputFormat $format = OutputFormat::ARRAY): mixed
    {
        try {
            if (! $this->cache) {
                $result = [
                    'status' => 'unavailable',
                    'message' => 'Cache system not configured',
                    'health_score' => 0,
                    'recommendations' => [
                        'Configure cache system for better performance',
                        'Consider Redis or APCu for production environments',
                    ],
                ];

                return $this->context->formatResult($result, $format);
            }

            // Comprehensive health check
            $testResults = $this->performCacheTests();
            $healthScore = $this->calculateCacheHealth($testResults);

            $result = [
                'status' => $this->getHealthStatus($healthScore),
                'health_score' => $healthScore,
                'test_results' => $testResults,
                'performance_metrics' => $this->getCachePerformanceMetrics(),
                'recommendations' => $this->getCacheRecommendations($testResults, $healthScore),
                'timestamp' => date('Y-m-d H:i:s'),
                'cache_info' => $this->getBasicCacheInfo(),
            ];

            return $this->context->formatResult($result, $format);
        } catch (\Throwable $e) {
            return $this->context->handleError($e, $format);
        }
    }

    #[McpTool(
        name: 'cache_info',
        description: 'Get detailed cache system configuration, features and capabilities',
        category: 'performance',
        tags: ['cache', 'configuration', 'features'],
        cacheable: true,
        defaultCacheTtl: 3600
    )]
    public function cacheInfo(OutputFormat $format = OutputFormat::ARRAY): mixed
    {
        try {
            if (! $this->cache) {
                $result = [
                    'status' => 'unavailable',
                    'message' => 'Cache system not configured',
                    'setup_guide' => [
                        'Configure a cache driver in your environment',
                        'Available drivers: Redis, APCu, File, In-Memory',
                        'Enable caching for better application performance',
                    ],
                ];

                return $this->context->formatResult($result, $format);
            }

            $result = [
                'status' => 'available',
                'cache_system' => [
                    'driver_type' => $this->detectCacheDriver(),
                    'configuration' => $this->getCacheConfiguration(),
                    'capabilities' => $this->getCacheCapabilities(),
                ],
                'features' => [
                    'multi_level_caching' => 'Hierarchical cache with multiple backends',
                    'compression_support' => 'Automatic data compression for large values',
                    'tagged_caching' => 'Tag-based cache invalidation',
                    'event_driven_invalidation' => 'Automatic cache invalidation on data changes',
                    'serialization_support' => 'Automatic object serialization/deserialization',
                    'ttl_management' => 'Time-to-live and expiration handling',
                    'atomic_operations' => 'Thread-safe cache operations',
                ],
                'supported_drivers' => [
                    'redis_cache' => 'High-performance distributed caching',
                    'apcu_cache' => 'In-memory cache for single server setups',
                    'file_cache' => 'Filesystem-based caching',
                    'in_memory_cache' => 'PHP runtime memory cache',
                    'null_cache' => 'No-op cache for development',
                ],
                'decorators' => [
                    'compression' => 'Reduces memory usage and network transfer',
                    'logging' => 'Cache operation logging and debugging',
                    'metrics' => 'Performance metrics collection',
                    'validation' => 'Data integrity validation',
                    'event_driven' => 'Event-based cache management',
                ],
                'performance_tips' => $this->getPerformanceTips(),
                'monitoring' => $this->getMonitoringInfo(),
                'timestamp' => date('Y-m-d H:i:s'),
            ];

            return $this->context->formatResult($result, $format);
        } catch (\Throwable $e) {
            return $this->context->handleError($e, $format);
        }
    }

    #[McpTool(
        name: 'cache_clear',
        description: 'Clear cache with safety confirmation (use with caution in production)',
        category: 'performance',
        tags: ['cache', 'clear', 'maintenance'],
        cacheable: false
    )]
    public function cacheClear(bool $confirm = false, string $scope = 'all', OutputFormat $format = OutputFormat::ARRAY): mixed
    {
        try {
            if (! $confirm) {
                $result = [
                    'status' => 'confirmation_required',
                    'message' => 'Cache clear requires explicit confirmation',
                    'usage' => 'Set confirm=true to proceed with cache clearing',
                    'warning' => 'This operation will clear cached data and may impact performance',
                    'scopes' => [
                        'all' => 'Clear entire cache (default)',
                        'expired' => 'Clear only expired entries',
                        'tag' => 'Clear by specific tag (requires tag parameter)',
                    ],
                    'safety_notes' => [
                        'Cache clearing will cause temporary performance degradation',
                        'Consider clearing during low-traffic periods',
                        'Monitor application performance after clearing',
                    ],
                ];

                return $this->context->formatResult($result, $format);
            }

            if (! $this->cache) {
                $result = [
                    'status' => 'unavailable',
                    'message' => 'Cache system not configured',
                ];

                return $this->context->formatResult($result, $format);
            }

            // Get cache statistics before clearing
            $preStats = $this->generateMockCacheStatistics();
            $clearResult = $this->performCacheClear($scope);

            $result = [
                'status' => $clearResult['success'] ? 'success' : 'partial_success',
                'message' => $clearResult['message'],
                'scope_cleared' => $scope,
                'statistics' => [
                    'pre_clear_stats' => $preStats,
                    'items_cleared' => $clearResult['items_cleared'] ?? 'unknown',
                    'clear_duration_ms' => $clearResult['duration_ms'] ?? 0,
                ],
                'timestamp' => date('Y-m-d H:i:s'),
                'warnings' => [
                    'Performance may be temporarily impacted',
                    'Cache will rebuild as application processes requests',
                    'Monitor response times for next few minutes',
                ],
                'next_steps' => [
                    'Monitor application performance',
                    'Cache will gradually rebuild with usage',
                    'Use cache_health_check to verify cache recovery',
                ],
            ];

            return $this->context->formatResult($result, $format);
        } catch (\Throwable $e) {
            return $this->context->handleError($e, $format);
        }
    }

    #[McpTool(
        name: 'cache_statistics',
        description: 'Get detailed cache usage statistics and performance metrics',
        category: 'performance',
        tags: ['cache', 'statistics', 'metrics'],
        cacheable: true,
        defaultCacheTtl: 300
    )]
    public function getCacheStatistics(OutputFormat $format = OutputFormat::ARRAY): mixed
    {
        try {
            if (! $this->cache) {
                $result = [
                    'status' => 'unavailable',
                    'message' => 'Cache system not configured',
                ];

                return $this->context->formatResult($result, $format);
            }

            $stats = $this->generateMockCacheStatistics();
            $performanceAnalysis = $this->analyzeCachePerformance($stats);

            $result = [
                'status' => 'available',
                'cache_statistics' => $stats,
                'performance_analysis' => $performanceAnalysis,
                'usage_patterns' => $this->analyzeCacheUsagePatterns(),
                'efficiency_metrics' => $this->calculateCacheEfficiency($stats),
                'recommendations' => $this->generateCacheOptimizationRecommendations($performanceAnalysis),
                'trending' => $this->getCacheTrends(),
                'timestamp' => date('Y-m-d H:i:s'),
            ];

            return $this->context->formatResult($result, $format);
        } catch (\Throwable $e) {
            return $this->context->handleError($e, $format);
        }
    }

    #[McpTool(
        name: 'cache_performance_test',
        description: 'Run comprehensive cache performance tests and benchmarks',
        category: 'performance',
        tags: ['cache', 'performance', 'benchmark'],
        cacheable: false
    )]
    public function runCachePerformanceTest(int $iterations = 100, OutputFormat $format = OutputFormat::ARRAY): mixed
    {
        try {
            if (! $this->cache) {
                $result = [
                    'status' => 'unavailable',
                    'message' => 'Cache system not configured',
                ];

                return $this->context->formatResult($result, $format);
            }

            $benchmarkResults = $this->runCacheBenchmarks($iterations);
            $performanceScore = $this->calculatePerformanceScore($benchmarkResults);

            $result = [
                'status' => 'completed',
                'test_configuration' => [
                    'iterations' => $iterations,
                    'test_types' => ['read', 'write', 'delete', 'bulk_operations'],
                    'data_sizes' => ['small (1KB)', 'medium (10KB)', 'large (100KB)'],
                ],
                'benchmark_results' => $benchmarkResults,
                'performance_score' => $performanceScore,
                'analysis' => [
                    'strengths' => $this->identifyPerformanceStrengths($benchmarkResults),
                    'weaknesses' => $this->identifyPerformanceWeaknesses($benchmarkResults),
                    'bottlenecks' => $this->identifyBottlenecks($benchmarkResults),
                ],
                'recommendations' => $this->generatePerformanceRecommendations($benchmarkResults),
                'comparison' => $this->getPerformanceBaseline($benchmarkResults),
                'timestamp' => date('Y-m-d H:i:s'),
                'test_duration_ms' => $benchmarkResults['total_duration_ms'] ?? 0,
            ];

            return $this->context->formatResult($result, $format);
        } catch (\Throwable $e) {
            return $this->context->handleError($e, $format);
        }
    }

    private function performCacheTests(): array
    {
        $tests = [];
        $startTime = microtime(true);

        try {
            // Basic read/write test
            $testKey = 'mcp_health_check_' . time();
            $testValue = 'test_' . random_int(1000, 9999);

            $writeStart = microtime(true);
            $this->cache->set($testKey, $testValue, 10);
            $writeTime = (microtime(true) - $writeStart) * 1000;

            $readStart = microtime(true);
            $retrieved = $this->cache->get($testKey);
            $readTime = (microtime(true) - $readStart) * 1000;

            $deleteStart = microtime(true);
            $this->cache->delete($testKey);
            $deleteTime = (microtime(true) - $deleteStart) * 1000;

            $tests['basic_operations'] = [
                'success' => $retrieved === $testValue,
                'write_time_ms' => round($writeTime, 2),
                'read_time_ms' => round($readTime, 2),
                'delete_time_ms' => round($deleteTime, 2),
            ];

            // Bulk operations test
            $bulkData = [];
            for ($i = 0; $i < 10; $i++) {
                $bulkData["bulk_test_key_$i"] = "bulk_value_$i";
            }

            $bulkStart = microtime(true);
            foreach ($bulkData as $key => $value) {
                $this->cache->set($key, $value, 10);
            }
            $bulkWriteTime = (microtime(true) - $bulkStart) * 1000;

            $bulkReadStart = microtime(true);
            $bulkRetrieved = 0;
            foreach (array_keys($bulkData) as $key) {
                if ($this->cache->get($key) !== null) {
                    $bulkRetrieved++;
                }
            }
            $bulkReadTime = (microtime(true) - $bulkReadStart) * 1000;

            // Cleanup bulk test data
            foreach (array_keys($bulkData) as $key) {
                $this->cache->delete($key);
            }

            $tests['bulk_operations'] = [
                'success' => $bulkRetrieved === 10,
                'items_tested' => 10,
                'items_retrieved' => $bulkRetrieved,
                'bulk_write_time_ms' => round($bulkWriteTime, 2),
                'bulk_read_time_ms' => round($bulkReadTime, 2),
            ];

        } catch (\Throwable $e) {
            $tests['error'] = [
                'success' => false,
                'message' => $e->getMessage(),
                'type' => get_class($e),
            ];
        }

        $tests['total_test_time_ms'] = round((microtime(true) - $startTime) * 1000, 2);

        return $tests;
    }

    private function calculateCacheHealth(array $testResults): int
    {
        $score = 100;

        // Basic operations health
        if (isset($testResults['basic_operations'])) {
            $basic = $testResults['basic_operations'];
            if (! $basic['success']) {
                $score -= 50;
            } else {
                // Performance scoring
                if ($basic['read_time_ms'] > 10) {
                    $score -= 10;
                }
                if ($basic['write_time_ms'] > 20) {
                    $score -= 10;
                }
                if ($basic['delete_time_ms'] > 15) {
                    $score -= 5;
                }
            }
        } else {
            $score -= 30;
        }

        // Bulk operations health
        if (isset($testResults['bulk_operations'])) {
            $bulk = $testResults['bulk_operations'];
            if (! $bulk['success']) {
                $score -= 30;
            } else {
                if ($bulk['bulk_read_time_ms'] > 50) {
                    $score -= 10;
                }
                if ($bulk['bulk_write_time_ms'] > 100) {
                    $score -= 10;
                }
            }
        } else {
            $score -= 20;
        }

        // Error penalty
        if (isset($testResults['error'])) {
            $score -= 40;
        }

        return max(0, min(100, $score));
    }

    private function getHealthStatus(int $score): string
    {
        return match (true) {
            $score >= 90 => 'excellent',
            $score >= 75 => 'good',
            $score >= 60 => 'fair',
            $score >= 40 => 'poor',
            default => 'critical'
        };
    }

    private function getCachePerformanceMetrics(): array
    {
        return [
            'operation_latency' => [
                'read_target_ms' => '< 5ms',
                'write_target_ms' => '< 10ms',
                'delete_target_ms' => '< 8ms',
            ],
            'throughput_targets' => [
                'reads_per_second' => '> 1000',
                'writes_per_second' => '> 500',
            ],
            'efficiency_targets' => [
                'hit_ratio' => '> 80%',
                'memory_usage' => '< 500MB',
            ],
        ];
    }

    private function getCacheRecommendations(array $testResults, int $healthScore): array
    {
        $recommendations = [];

        if ($healthScore < 70) {
            $recommendations[] = 'Consider upgrading cache infrastructure';
        }

        if (isset($testResults['basic_operations'])) {
            $basic = $testResults['basic_operations'];
            if ($basic['read_time_ms'] > 10) {
                $recommendations[] = 'Optimize cache read performance';
            }
            if ($basic['write_time_ms'] > 20) {
                $recommendations[] = 'Optimize cache write performance';
            }
        }

        if (empty($recommendations)) {
            $recommendations[] = 'Cache performance is optimal';
        }

        return $recommendations;
    }

    private function getBasicCacheInfo(): array
    {
        return [
            'driver_detected' => $this->detectCacheDriver(),
            'features_available' => $this->getCacheCapabilities(),
            'configuration_status' => 'active',
        ];
    }

    private function detectCacheDriver(): string
    {
        // Simplified driver detection
        return 'framework_cache_implementation';
    }

    private function getCacheConfiguration(): array
    {
        return [
            'default_ttl' => '3600 seconds',
            'compression_enabled' => true,
            'serialization' => 'automatic',
            'tag_support' => true,
        ];
    }

    private function getCacheCapabilities(): array
    {
        return [
            'atomic_operations',
            'batch_operations',
            'ttl_support',
            'tag_based_invalidation',
            'compression',
            'serialization',
            'event_integration',
        ];
    }

    private function getPerformanceTips(): array
    {
        return [
            'Use appropriate TTL values to balance freshness and performance',
            'Implement cache warming for critical data',
            'Use tags for efficient cache invalidation',
            'Monitor cache hit ratios regularly',
            'Consider cache preloading for frequently accessed data',
        ];
    }

    private function getMonitoringInfo(): array
    {
        return [
            'key_metrics' => ['hit_ratio', 'response_time', 'memory_usage'],
            'alert_thresholds' => [
                'hit_ratio_below' => '70%',
                'response_time_above' => '50ms',
                'memory_usage_above' => '80%',
            ],
            'monitoring_tools' => ['cache_health_check', 'cache_statistics'],
        ];
    }

    private function performCacheClear(string $scope): array
    {
        $startTime = microtime(true);

        try {
            switch ($scope) {
                case 'all':
                    $this->cache->clear();
                    $message = 'All cache entries cleared successfully';

                    break;
                case 'expired':
                    // Note: This would require cache driver support
                    $message = 'Expired entries cleared (if supported by driver)';

                    break;
                default:
                    $this->cache->clear();
                    $message = 'Cache cleared with default scope';
            }

            $duration = (microtime(true) - $startTime) * 1000;

            return [
                'success' => true,
                'message' => $message,
                'duration_ms' => round($duration, 2),
                'items_cleared' => 'all',
            ];
        } catch (\Throwable $e) {
            return [
                'success' => false,
                'message' => 'Cache clear failed: ' . $e->getMessage(),
                'duration_ms' => round((microtime(true) - $startTime) * 1000, 2),
            ];
        }
    }

    private function generateMockCacheStatistics(): array
    {
        // Mock statistics - in real implementation, this would query actual cache metrics
        return [
            'total_keys' => random_int(100, 1000),
            'memory_usage_mb' => round(random_int(10, 100), 2),
            'hit_ratio_percent' => round(random_int(70, 95), 1),
            'operations_per_second' => random_int(100, 500),
            'average_response_time_ms' => round(random_int(1, 10), 2),
        ];
    }

    private function analyzeCachePerformance(array $stats): array
    {
        return [
            'performance_status' => $stats['hit_ratio_percent'] > 80 ? 'good' : 'needs_improvement',
            'memory_efficiency' => $stats['memory_usage_mb'] < 100 ? 'efficient' : 'high_usage',
            'response_time_analysis' => $stats['average_response_time_ms'] < 5 ? 'excellent' : 'acceptable',
        ];
    }

    private function analyzeCacheUsagePatterns(): array
    {
        return [
            'peak_usage_hours' => '09:00-17:00',
            'cache_miss_patterns' => 'Higher during deployment',
            'frequent_keys' => 'user_sessions, api_responses, computed_data',
        ];
    }

    private function calculateCacheEfficiency(array $stats): array
    {
        return [
            'hit_ratio_score' => min(100, $stats['hit_ratio_percent']),
            'response_time_score' => max(0, 100 - ($stats['average_response_time_ms'] * 10)),
            'memory_efficiency_score' => max(0, 100 - ($stats['memory_usage_mb'] / 5)),
        ];
    }

    private function generateCacheOptimizationRecommendations(array $performanceAnalysis): array
    {
        $recommendations = [];

        if ($performanceAnalysis['performance_status'] === 'needs_improvement') {
            $recommendations[] = 'Optimize cache key structure and TTL values';
        }

        if ($performanceAnalysis['memory_efficiency'] === 'high_usage') {
            $recommendations[] = 'Consider cache eviction policies and compression';
        }

        return $recommendations;
    }

    private function getCacheTrends(): array
    {
        return [
            'hit_ratio_trend' => 'stable',
            'memory_usage_trend' => 'increasing',
            'response_time_trend' => 'stable',
        ];
    }

    private function runCacheBenchmarks(int $iterations): array
    {
        $results = [];
        $startTime = microtime(true);

        // Read benchmark
        $readTimes = [];
        for ($i = 0; $i < $iterations; $i++) {
            $key = "benchmark_read_$i";
            $this->cache->set($key, "value_$i", 60);

            $readStart = microtime(true);
            $this->cache->get($key);
            $readTimes[] = (microtime(true) - $readStart) * 1000;

            $this->cache->delete($key);
        }

        $results['read_benchmark'] = [
            'iterations' => $iterations,
            'avg_time_ms' => round(array_sum($readTimes) / count($readTimes), 3),
            'min_time_ms' => round(min($readTimes), 3),
            'max_time_ms' => round(max($readTimes), 3),
        ];

        // Write benchmark
        $writeTimes = [];
        for ($i = 0; $i < $iterations; $i++) {
            $key = "benchmark_write_$i";

            $writeStart = microtime(true);
            $this->cache->set($key, "value_$i", 60);
            $writeTimes[] = (microtime(true) - $writeStart) * 1000;

            $this->cache->delete($key);
        }

        $results['write_benchmark'] = [
            'iterations' => $iterations,
            'avg_time_ms' => round(array_sum($writeTimes) / count($writeTimes), 3),
            'min_time_ms' => round(min($writeTimes), 3),
            'max_time_ms' => round(max($writeTimes), 3),
        ];

        $results['total_duration_ms'] = round((microtime(true) - $startTime) * 1000, 2);

        return $results;
    }

    private function calculatePerformanceScore(array $benchmarkResults): int
    {
        $score = 100;

        $readAvg = $benchmarkResults['read_benchmark']['avg_time_ms'] ?? 0;
        $writeAvg = $benchmarkResults['write_benchmark']['avg_time_ms'] ?? 0;

        // Penalize slow operations
        if ($readAvg > 10) {
            $score -= 20;
        }
        if ($writeAvg > 20) {
            $score -= 20;
        }
        if ($readAvg > 5) {
            $score -= 10;
        }
        if ($writeAvg > 10) {
            $score -= 10;
        }

        return max(0, $score);
    }

    private function identifyPerformanceStrengths(array $benchmarkResults): array
    {
        $strengths = [];

        if (($benchmarkResults['read_benchmark']['avg_time_ms'] ?? 0) < 5) {
            $strengths[] = 'Excellent read performance';
        }

        if (($benchmarkResults['write_benchmark']['avg_time_ms'] ?? 0) < 10) {
            $strengths[] = 'Good write performance';
        }

        return $strengths;
    }

    private function identifyPerformanceWeaknesses(array $benchmarkResults): array
    {
        $weaknesses = [];

        if (($benchmarkResults['read_benchmark']['avg_time_ms'] ?? 0) > 10) {
            $weaknesses[] = 'Slow read operations';
        }

        if (($benchmarkResults['write_benchmark']['avg_time_ms'] ?? 0) > 20) {
            $weaknesses[] = 'Slow write operations';
        }

        return $weaknesses;
    }

    private function identifyBottlenecks(array $benchmarkResults): array
    {
        $bottlenecks = [];

        $readMax = $benchmarkResults['read_benchmark']['max_time_ms'] ?? 0;
        $writeMax = $benchmarkResults['write_benchmark']['max_time_ms'] ?? 0;

        if ($readMax > 50) {
            $bottlenecks[] = 'Occasional slow read operations detected';
        }

        if ($writeMax > 100) {
            $bottlenecks[] = 'Occasional slow write operations detected';
        }

        return $bottlenecks;
    }

    private function generatePerformanceRecommendations(array $benchmarkResults): array
    {
        $recommendations = [];

        if (($benchmarkResults['read_benchmark']['avg_time_ms'] ?? 0) > 5) {
            $recommendations[] = 'Optimize cache read operations';
        }

        if (($benchmarkResults['write_benchmark']['avg_time_ms'] ?? 0) > 10) {
            $recommendations[] = 'Optimize cache write operations';
        }

        if (empty($recommendations)) {
            $recommendations[] = 'Cache performance is within optimal ranges';
        }

        return $recommendations;
    }

    private function getPerformanceBaseline(array $benchmarkResults): array
    {
        return [
            'industry_standards' => [
                'read_target_ms' => '< 5ms',
                'write_target_ms' => '< 10ms',
            ],
            'current_performance' => [
                'read_avg_ms' => $benchmarkResults['read_benchmark']['avg_time_ms'] ?? 0,
                'write_avg_ms' => $benchmarkResults['write_benchmark']['avg_time_ms'] ?? 0,
            ],
        ];
    }
}
