<?php

namespace App\Services\Core;

use App\Services\Analytics\EventBus;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
use App\Models\User;
use App\Models\Setting;

class HealthCheckService
{
    private ConfigurationManager $configManager;
    private EventBus $eventBus;

    public function __construct(ConfigurationManager $configManager, EventBus $eventBus)
    {
        $this->configManager = $configManager;
        $this->eventBus = $eventBus;
    }

    /**
     * Run all health checks and return results
     */
    public function runAllChecks(): array
    {
        $results = [];
        
        $checks = [
            'database' => [$this, 'checkDatabase'],
            'cache' => [$this, 'checkCache'],
            'telegram_api' => [$this, 'checkTelegramApi'],
            'storage' => [$this, 'checkStorage'],
            'configuration' => [$this, 'checkConfiguration'],
            'system_resources' => [$this, 'checkSystemResources'],
        ];

        foreach ($checks as $name => $callable) {
            try {
                $startTime = microtime(true);
                $result = call_user_func($callable);
                $duration = round((microtime(true) - $startTime) * 1000, 2); // ms

                $results[$name] = [
                    'status' => $result['status'] ?? 'error',
                    'message' => $result['message'] ?? 'Unknown error',
                    'details' => $result['details'] ?? [],
                    'duration_ms' => $duration,
                    'timestamp' => now()->toISOString(),
                ];
            } catch (\Throwable $e) {
                $results[$name] = [
                    'status' => 'error',
                    'message' => $e->getMessage(),
                    'details' => [],
                    'duration_ms' => 0,
                    'timestamp' => now()->toISOString(),
                ];
                
                Log::error('Health check failed: ' . $name, [
                    'error' => $e->getMessage(),
                    'trace' => $e->getTraceAsString()
                ]);
            }
        }

        // Calculate overall health status
        $overallStatus = $this->calculateOverallStatus($results);
        
        // Emit health check event
        $this->eventBus->emit('system.health_check_completed', [
            'overall_status' => $overallStatus,
            'results' => $results,
            'timestamp' => now()->toISOString(),
        ]);

        return [
            'overall_status' => $overallStatus,
            'checks' => $results,
            'summary' => $this->generateSummary($results),
        ];
    }

    /**
     * Check database connectivity and performance
     */
    private function checkDatabase(): array
    {
        try {
            // Basic connectivity
            $startTime = microtime(true);
            DB::select('SELECT 1');
            $connectionTime = round((microtime(true) - $startTime) * 1000, 2);

            // Check user count
            $userCount = User::count();
            
            // Check settings count
            $settingsCount = Setting::count();

            // Check for recent activity
            $recentUsers = User::where('updated_at', '>=', now()->subHours(24))->count();

            $details = [
                'connection_time_ms' => $connectionTime,
                'total_users' => $userCount,
                'total_settings' => $settingsCount,
                'active_users_24h' => $recentUsers,
            ];

            $status = $connectionTime < 1000 ? 'healthy' : 'warning';
            $message = $connectionTime < 1000 
                ? 'Database is responding normally'
                : 'Database response time is slower than expected';

            return [
                'status' => $status,
                'message' => $message,
                'details' => $details,
            ];
        } catch (\Exception $e) {
            return [
                'status' => 'error',
                'message' => 'Database connection failed: ' . $e->getMessage(),
                'details' => [],
            ];
        }
    }

    /**
     * Check cache system
     */
    private function checkCache(): array
    {
        try {
            $testKey = 'health_check_' . time();
            $testValue = 'test_value';

            // Test cache write
            Cache::put($testKey, $testValue, 60);
            
            // Test cache read
            $retrieved = Cache::get($testKey);
            
            // Clean up
            Cache::forget($testKey);

            $isWorking = $retrieved === $testValue;

            return [
                'status' => $isWorking ? 'healthy' : 'error',
                'message' => $isWorking 
                    ? 'Cache is working properly'
                    : 'Cache read/write test failed',
                'details' => [
                    'driver' => config('cache.default'),
                    'test_passed' => $isWorking,
                ],
            ];
        } catch (\Exception $e) {
            return [
                'status' => 'error',
                'message' => 'Cache system error: ' . $e->getMessage(),
                'details' => [],
            ];
        }
    }

    /**
     * Check Telegram API connectivity
     */
    private function checkTelegramApi(): array
    {
        try {
            $botToken = $this->configManager->get('telegram.bot_token');
            
            if (!$botToken) {
                return [
                    'status' => 'warning',
                    'message' => 'Telegram bot token not configured',
                    'details' => [],
                ];
            }

            // Test API call
            $response = Http::timeout(10)->get("https://api.telegram.org/bot{$botToken}/getMe");

            if ($response->successful()) {
                $botInfo = $response->json();
                
                return [
                    'status' => 'healthy',
                    'message' => 'Telegram API is accessible',
                    'details' => [
                        'bot_username' => $botInfo['result']['username'] ?? 'unknown',
                        'bot_name' => $botInfo['result']['first_name'] ?? 'unknown',
                        'can_join_groups' => $botInfo['result']['can_join_groups'] ?? false,
                        'can_read_all_group_messages' => $botInfo['result']['can_read_all_group_messages'] ?? false,
                    ],
                ];
            } else {
                return [
                    'status' => 'error',
                    'message' => 'Telegram API returned error: ' . $response->status(),
                    'details' => [
                        'status_code' => $response->status(),
                        'response' => $response->body(),
                    ],
                ];
            }
        } catch (\Exception $e) {
            return [
                'status' => 'error',
                'message' => 'Failed to connect to Telegram API: ' . $e->getMessage(),
                'details' => [],
            ];
        }
    }

    /**
     * Check storage system
     */
    private function checkStorage(): array
    {
        try {
            $storagePath = storage_path();
            $isWritable = is_writable($storagePath);
            
            // Check disk space
            $freeSpace = disk_free_space($storagePath);
            $totalSpace = disk_total_space($storagePath);
            $usagePercent = round(((($totalSpace - $freeSpace) / $totalSpace) * 100), 2);

            $status = 'healthy';
            $message = 'Storage is accessible';

            if (!$isWritable) {
                $status = 'error';
                $message = 'Storage directory is not writable';
            } elseif ($usagePercent > 90) {
                $status = 'error';
                $message = 'Disk usage is critically high';
            } elseif ($usagePercent > 80) {
                $status = 'warning';
                $message = 'Disk usage is high';
            }

            return [
                'status' => $status,
                'message' => $message,
                'details' => [
                    'path' => $storagePath,
                    'writable' => $isWritable,
                    'free_space_gb' => round($freeSpace / (1024 ** 3), 2),
                    'total_space_gb' => round($totalSpace / (1024 ** 3), 2),
                    'usage_percent' => $usagePercent,
                ],
            ];
        } catch (\Exception $e) {
            return [
                'status' => 'error',
                'message' => 'Storage check failed: ' . $e->getMessage(),
                'details' => [],
            ];
        }
    }

    /**
     * Check configuration system
     */
    private function checkConfiguration(): array
    {
        try {
            // Test configuration reading
            $testConfig = $this->configManager->get('app.name', 'default');
            
            // Check critical settings
            $criticalSettings = [
                'telegram.bot_token',
                'app.name',
                'app.timezone',
            ];
            
            $missingSettings = [];
            foreach ($criticalSettings as $setting) {
                if (!$this->configManager->has($setting)) {
                    $missingSettings[] = $setting;
                }
            }

            $status = empty($missingSettings) ? 'healthy' : 'warning';
            $message = empty($missingSettings) 
                ? 'Configuration system is working'
                : 'Some critical settings are missing';

            return [
                'status' => $status,
                'message' => $message,
                'details' => [
                    'test_read' => $testConfig !== null,
                    'missing_settings' => $missingSettings,
                    'total_settings' => Setting::count(),
                ],
            ];
        } catch (\Exception $e) {
            return [
                'status' => 'error',
                'message' => 'Configuration check failed: ' . $e->getMessage(),
                'details' => [],
            ];
        }
    }

    /**
     * Check system resources
     */
    private function checkSystemResources(): array
    {
        try {
            $memoryUsage = memory_get_usage(true);
            $memoryLimit = ini_get('memory_limit');
            $memoryLimitBytes = $this->convertToBytes($memoryLimit);
            
            $memoryPercent = $memoryLimitBytes > 0 
                ? round(($memoryUsage / $memoryLimitBytes) * 100, 2)
                : 0;

            $status = 'healthy';
            $message = 'System resources are normal';

            if ($memoryPercent > 90) {
                $status = 'error';
                $message = 'Memory usage is critically high';
            } elseif ($memoryPercent > 80) {
                $status = 'warning';
                $message = 'Memory usage is high';
            }

            return [
                'status' => $status,
                'message' => $message,
                'details' => [
                    'memory_usage_mb' => round($memoryUsage / (1024 ** 2), 2),
                    'memory_limit' => $memoryLimit,
                    'memory_usage_percent' => $memoryPercent,
                    'php_version' => PHP_VERSION,
                    'laravel_version' => app()->version(),
                ],
            ];
        } catch (\Exception $e) {
            return [
                'status' => 'error',
                'message' => 'System resource check failed: ' . $e->getMessage(),
                'details' => [],
            ];
        }
    }

    /**
     * Calculate overall health status
     */
    private function calculateOverallStatus(array $results): string
    {
        $errorCount = 0;
        $warningCount = 0;

        foreach ($results as $result) {
            if ($result['status'] === 'error') {
                $errorCount++;
            } elseif ($result['status'] === 'warning') {
                $warningCount++;
            }
        }

        if ($errorCount > 0) {
            return 'error';
        } elseif ($warningCount > 0) {
            return 'warning';
        }

        return 'healthy';
    }

    /**
     * Generate health check summary
     */
    private function generateSummary(array $results): array
    {
        $summary = [
            'total_checks' => count($results),
            'healthy' => 0,
            'warning' => 0,
            'error' => 0,
        ];

        foreach ($results as $result) {
            $summary[$result['status']]++;
        }

        return $summary;
    }

    /**
     * Convert PHP memory limit to bytes
     */
    private function convertToBytes(string $value): int
    {
        $unit = strtolower(substr($value, -1));
        $number = (int) substr($value, 0, -1);

        return match ($unit) {
            'g' => $number * (1024 ** 3),
            'm' => $number * (1024 ** 2),
            'k' => $number * 1024,
            default => (int) $value,
        };
    }
}