<?php

namespace App\Services;

use App\Models\Order;
use App\Models\Trade;
use App\Models\Wallet;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Redis;

class MonitoringService
{
    /**
     * Monitor system metrics and performance
     */
    public function monitorSystemMetrics(): array
    {
        try {
            $metrics = [
                'timestamp' => now()->toISOString(),
                'system_metrics' => [
                    'open_orders_count' => Order::active()->count(),
                    'completed_orders_today' => Order::completed()->whereDate('created_at', today())->count(),
                    'pending_orders' => Order::where('status', 'pending')->count(),
                    'active_users' => Redis::scard('active_users'),
                    'redis_connections' => $this->getRedisConnections(),
                    'memory_usage' => memory_get_usage(true),
                    'memory_peak_usage' => memory_get_peak_usage(true),
                ],
                'market_metrics' => $this->getMarketMetrics(),
                'wallet_metrics' => $this->getWalletMetrics(),
                'system_health' => $this->checkSystemHealth(),
            ];
            
            // Log system metrics
            Log::info('System metrics monitoring', $metrics);
            
            return $metrics;
        } catch (\Exception $e) {
            Log::error('Monitoring service error: ' . $e->getMessage());
            return ['error' => $e->getMessage()];
        }
    }
    
    /**
     * Get Redis connections count
     */
    private function getRedisConnections(): int
    {
        try {
            $redis = Redis::connection();
            $info = $redis->info('clients');
            return $info['connected_clients'] ?? 0;
        } catch (\Exception $e) {
            Log::error('Redis monitoring error: ' . $e->getMessage());
            return 0;
        }
    }
    
    /**
     * Get market-related metrics
     */
    private function getMarketMetrics(): array
    {
        $metrics = [
            'total_trades_24h' => Trade::where('created_at', '>=', now()->subDay())->count(),
            'total_trade_volume_24h' => Trade::where('created_at', '>=', now()->subDay())->sum('price'),
            'top_trading_pairs' => [],
            'market_making_liquidity' => $this->checkMarketLiquidity(),
            'last_price_changes' => $this->getPriceMovements(),
        ];
        
        try {
            // Get top trading pairs by volume
            $topPairs = Trade::selectRaw('market_id, COUNT(*) as trade_count, SUM(price * quantity) as volume')
                ->where('created_at', '>=', now()->subDay())
                ->groupBy('market_id')
                ->orderByDesc('volume')
                ->limit(5)
                ->get();
                
            $metrics['top_trading_pairs'] = $topPairs->toArray();
        } catch (\Exception $e) {
            Log::error('Market metrics error: ' . $e->getMessage());
        }
        
        return $metrics;
    }
    
    /**
     * Get wallet-related metrics
     */
    private function getWalletMetrics(): array
    {
        return [
            'total_wallets' => Wallet::count(),
            'total_locked_balance' => Wallet::sum('locked_balance'),
            'total_available_balance' => Wallet::sum('available_balance'),
            'wallets_with_high_activity' => $this->getActiveWallets(),
        ];
    }
    
    /**
     * Get wallets with high trading activity
     */
    private function getActiveWallets(): array
    {
        try {
            return Wallet::whereHas('orders', function ($query) {
                $query->where('created_at', '>=', now()->subDay());
            })->withCount(['orders' => function ($query) {
                $query->where('created_at', '>=', now()->subDay());
            }])->orderByDesc('orders_count')->limit(10)->get()->toArray();
        } catch (\Exception $e) {
            Log::error('Active wallets error: ' . $e->getMessage());
            return [];
        }
    }
    
    /**
     * Check system health status
     */
    private function checkSystemHealth(): array
    {
        $health = [
            'database' => $this->checkDatabaseHealth(),
            'redis' => $this->checkRedisHealth(),
            'queue' => $this->checkQueueHealth(),
            'overall_status' => 'healthy',
        ];
        
        // Determine overall system health
        if (in_array('unhealthy', array_values($health))) {
            $health['overall_status'] = 'unhealthy';
        } elseif (in_array('degraded', array_values($health))) {
            $health['overall_status'] = 'degraded';
        }
        
        return $health;
    }
    
    /**
     * Check database health
     */
    private function checkDatabaseHealth(): string
    {
        try {
            \DB::connection()->getPdo();
            return 'healthy';
        } catch (\Exception $e) {
            Log::error('Database health check failed: ' . $e->getMessage());
            return 'unhealthy';
        }
    }
    
    /**
     * Check Redis health
     */
    private function checkRedisHealth(): string
    {
        try {
            $redis = Redis::connection();
            $redis->ping();
            return 'healthy';
        } catch (\Exception $e) {
            Log::error('Redis health check failed: ' . $e->getMessage());
            return 'unhealthy';
        }
    }
    
    /**
     * Check queue health
     */
    private function checkQueueHealth(): string
    {
        try {
            // Check if queue workers are processing jobs
            $failedJobs = \DB::table('failed_jobs')->where('failed_at', '>=', now()->subHour())->count();
            $pendingJobs = \DB::table('jobs')->count();
            
            if ($failedJobs > 10) {
                return 'degraded';
            } elseif ($pendingJobs > 1000) {
                return 'degraded';
            }
            
            return 'healthy';
        } catch (\Exception $e) {
            Log::error('Queue health check failed: ' . $e->getMessage());
            return 'unhealthy';
        }
    }
    
    /**
     * Check market liquidity
     */
    private function checkMarketLiquidity(): array
    {
        try {
            $markets = \App\Models\Market::active()->get();
            $liquidity = [];
            
            foreach ($markets as $market) {
                $openOrders = Order::forMarket($market->id)->active()->count();
                $recentTrades = Trade::forMarket($market->id)->where('created_at', '>=', now()->subHour())->count();
                
                $liquidity[$market->id] = [
                    'open_orders' => $openOrders,
                    'recent_trades' => $recentTrades,
                    'liquidity_score' => $this->calculateLiquidityScore($openOrders, $recentTrades),
                ];
            }
            
            return $liquidity;
        } catch (\Exception $e) {
            Log::error('Market liquidity check failed: ' . $e->getMessage());
            return [];
        }
    }
    
    /**
     * Calculate liquidity score
     */
    private function calculateLiquidityScore(int $openOrders, int $recentTrades): float
    {
        // Simple liquidity scoring algorithm
        $score = 0;
        
        if ($openOrders >= 10) {
            $score += 50; // Good order depth
        } elseif ($openOrders >= 5) {
            $score += 30;
        } else {
            $score += 10;
        }
        
        if ($recentTrades >= 50) {
            $score += 50; // Good trading activity
        } elseif ($recentTrades >= 20) {
            $score += 30;
        } else {
            $score += 10;
        }
        
        return min($score, 100); // Cap at 100
    }
    
    /**
     * Get price movements for recent trades
     */
    private function getPriceMovements(): array
    {
        try {
            $movements = [];
            $markets = \App\Models\Market::active()->get();
            
            foreach ($markets as $market) {
                $recentTrades = Trade::forMarket($market->id)
                    ->orderByDesc('created_at')
                    ->limit(10)
                    ->get();
                
                if ($recentTrades->count() >= 2) {
                    $firstPrice = $recentTrades->last()->price;
                    $lastPrice = $recentTrades->first()->price;
                    $change = $lastPrice - $firstPrice;
                    $changePercent = ($change / $firstPrice) * 100;
                    
                    $movements[$market->id] = [
                        'current_price' => $lastPrice,
                        'price_change' => $change,
                        'price_change_percent' => round($changePercent, 2),
                        'volume' => $recentTrades->sum('quantity'),
                    ];
                }
            }
            
            return $movements;
        } catch (\Exception $e) {
            Log::error('Price movements error: ' . $e->getMessage());
            return [];
        }
    }
}