<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\File;

class DevelopmentWebhook extends Command
{
    protected $signature = 'dev:webhook 
                            {action : start, stop, or status}
                            {--port=8000 : Local server port}
                            {--ngrok : Use ngrok for tunneling}
                            {--expose : Use Laravel Expose for tunneling}';
    
    protected $description = 'Manage development webhook for local testing';

    private $tunnelProcess = null;

    public function handle()
    {
        $action = $this->argument('action');
        
        switch ($action) {
            case 'start':
                return $this->startDevelopmentWebhook();
            case 'stop':
                return $this->stopDevelopmentWebhook();
            case 'status':
                return $this->checkWebhookStatus();
            default:
                $this->error('Invalid action. Use: start, stop, or status');
                return 1;
        }
    }
    
    private function startDevelopmentWebhook()
    {
        $this->info('🚀 Starting Development Webhook Setup');
        $this->line('===================================');
        
        // Check if bot token is configured
        $botToken = config('telegram.bot_token') ?? env('TELEGRAM_BOT_TOKEN');
        if (empty($botToken)) {
            $this->error('❌ Telegram bot token not configured!');
            $this->line('Please set TELEGRAM_BOT_TOKEN in your .env file');
            return 1;
        }
        
        // Choose tunneling method
        $tunnelMethod = $this->chooseTunnelMethod();
        
        if (!$tunnelMethod) {
            $this->error('No tunneling method available!');
            return 1;
        }
        
        // Start local server
        $port = $this->option('port');
        $this->startLocalServer($port);
        
        // Start tunnel
        $tunnelUrl = $this->startTunnel($tunnelMethod, $port);
        
        if (!$tunnelUrl) {
            $this->error('Failed to create tunnel!');
            return 1;
        }
        
        // Set webhook
        $webhookUrl = $tunnelUrl . '/api/telegram/webhook';
        if ($this->setTelegramWebhook($webhookUrl, $botToken)) {
            $this->info("✅ Development webhook set successfully!");
            $this->line("Webhook URL: {$webhookUrl}");
            $this->line("Local server: http://localhost:{$port}");
            $this->line("Admin panel: {$tunnelUrl}/admin");
            
            // Save tunnel info for later cleanup
            $this->saveTunnelInfo($tunnelMethod, $tunnelUrl, $port);
            
            $this->newLine();
            $this->info('🎯 Your bot is now ready for development testing!');
            $this->line('Send /start to your bot on Telegram to test.');
            $this->line('Press Ctrl+C to stop the development server.');
            
            // Keep the process running
            $this->keepAlive();
        }
        
        return 0;
    }
    
    private function chooseTunnelMethod()
    {
        if ($this->option('ngrok')) {
            return $this->checkNgrok() ? 'ngrok' : null;
        }
        
        if ($this->option('expose')) {
            return $this->checkExpose() ? 'expose' : null;
        }
        
        // Auto-detect available methods
        if ($this->checkNgrok()) {
            if ($this->confirm('Use ngrok for tunneling?', true)) {
                return 'ngrok';
            }
        }
        
        if ($this->checkExpose()) {
            if ($this->confirm('Use Laravel Expose for tunneling?', true)) {
                return 'expose';
            }
        }
        
        // Fallback options
        $this->line('No tunneling tools detected. Available options:');
        $this->line('1. Install ngrok: https://ngrok.com/download');
        $this->line('2. Install Laravel Expose: composer global require beyondcode/expose');
        $this->line('3. Use a custom tunnel service');
        
        if ($this->confirm('Do you have a custom tunnel URL?', false)) {
            return 'custom';
        }
        
        return null;
    }
    
    private function checkNgrok()
    {
        return $this->commandExists('ngrok');
    }
    
    private function checkExpose()
    {
        return $this->commandExists('expose');
    }
    
    private function startLocalServer($port)
    {
        $this->info("Starting local Laravel server on port {$port}...");
        
        // Start server in background
        $serverCommand = "php artisan serve --port={$port} > /dev/null 2>&1 &";
        exec($serverCommand);
        
        // Wait for server to start
        sleep(2);
        
        // Verify server is running
        $response = Http::timeout(5)->get("http://localhost:{$port}");
        if ($response->successful()) {
            $this->info("✅ Local server started successfully");
        } else {
            $this->warn("⚠️  Server may not be fully ready yet");
        }
    }
    
    private function startTunnel($method, $port)
    {
        switch ($method) {
            case 'ngrok':
                return $this->startNgrokTunnel($port);
            case 'expose':
                return $this->startExposeTunnel($port);
            case 'custom':
                return $this->getCustomTunnelUrl();
            default:
                return null;
        }
    }
    
    private function startNgrokTunnel($port)
    {
        $this->info("Starting ngrok tunnel...");
        
        // Start ngrok in background
        $ngrokCommand = "ngrok http {$port} --log=stdout > storage/logs/ngrok.log 2>&1 &";
        exec($ngrokCommand);
        
        // Wait for ngrok to start
        sleep(5);
        
        // Get ngrok URL from API
        try {
            $response = Http::get('http://127.0.0.1:4040/api/tunnels');
            if ($response->successful()) {
                $tunnels = $response->json()['tunnels'];
                foreach ($tunnels as $tunnel) {
                    if ($tunnel['config']['addr'] === "http://localhost:{$port}") {
                        $url = $tunnel['public_url'];
                        if (strpos($url, 'https://') === 0) {
                            $this->info("✅ Ngrok tunnel created: {$url}");
                            return $url;
                        }
                    }
                }
            }
        } catch (\Exception $e) {
            $this->error("Failed to get ngrok URL: " . $e->getMessage());
        }
        
        return null;
    }
    
    private function startExposeTunnel($port)
    {
        $this->info("Starting Laravel Expose tunnel...");
        
        // Start expose in background
        $exposeCommand = "expose {$port} --log-file=storage/logs/expose.log > /dev/null 2>&1 &";
        exec($exposeCommand);
        
        sleep(3);
        
        // For now, we'll need the user to provide the URL
        // Expose doesn't have an easy API to get the URL programmatically
        $url = $this->ask('Please enter the Expose tunnel URL (should be shown in the terminal)');
        
        if ($url && filter_var($url, FILTER_VALIDATE_URL)) {
            $this->info("✅ Expose tunnel confirmed: {$url}");
            return $url;
        }
        
        return null;
    }
    
    private function getCustomTunnelUrl()
    {
        $url = $this->ask('Enter your tunnel URL (e.g., https://abc123.ngrok.io)');
        
        if ($url && filter_var($url, FILTER_VALIDATE_URL)) {
            return rtrim($url, '/');
        }
        
        $this->error('Invalid URL provided');
        return null;
    }
    
    private function setTelegramWebhook($webhookUrl, $botToken)
    {
        $this->info("Setting Telegram webhook to: {$webhookUrl}");
        
        $response = Http::post("https://api.telegram.org/bot{$botToken}/setWebhook", [
            'url' => $webhookUrl,
            'drop_pending_updates' => true,
        ]);
        
        if ($response->successful()) {
            $result = $response->json();
            if ($result['ok']) {
                return true;
            } else {
                $this->error('Webhook setup failed: ' . $result['description']);
                return false;
            }
        }
        
        $this->error('Failed to communicate with Telegram API');
        return false;
    }
    
    private function saveTunnelInfo($method, $url, $port)
    {
        $info = [
            'method' => $method,
            'url' => $url,
            'port' => $port,
            'started_at' => now()->toISOString(),
            'pid' => getmypid(),
        ];
        
        File::put(storage_path('app/dev_tunnel.json'), json_encode($info, JSON_PRETTY_PRINT));
    }
    
    private function stopDevelopmentWebhook()
    {
        $this->info('🛑 Stopping Development Webhook');
        $this->line('===============================');
        
        // Get tunnel info
        $tunnelInfoPath = storage_path('app/dev_tunnel.json');
        if (!File::exists($tunnelInfoPath)) {
            $this->warn('No active development webhook found');
            return 0;
        }
        
        $tunnelInfo = json_decode(File::get($tunnelInfoPath), true);
        
        // Remove webhook
        $botToken = config('telegram.bot_token') ?? env('TELEGRAM_BOT_TOKEN');
        if ($botToken) {
            $this->info('Removing Telegram webhook...');
            Http::post("https://api.telegram.org/bot{$botToken}/deleteWebhook");
            $this->info('✅ Webhook removed');
        }
        
        // Stop tunnel processes
        $this->stopTunnelProcesses($tunnelInfo['method']);
        
        // Clean up
        File::delete($tunnelInfoPath);
        
        $this->info('✅ Development webhook stopped successfully');
        return 0;
    }
    
    private function stopTunnelProcesses($method)
    {
        switch ($method) {
            case 'ngrok':
                exec('pkill -f ngrok');
                $this->info('✅ Ngrok processes stopped');
                break;
            case 'expose':
                exec('pkill -f expose');
                $this->info('✅ Expose processes stopped');
                break;
        }
        
        // Also stop any Laravel development servers
        exec('pkill -f "php artisan serve"');
        $this->info('✅ Local server stopped');
    }
    
    private function checkWebhookStatus()
    {
        $this->info('📊 Development Webhook Status');
        $this->line('=============================');
        
        // Check tunnel info
        $tunnelInfoPath = storage_path('app/dev_tunnel.json');
        if (File::exists($tunnelInfoPath)) {
            $tunnelInfo = json_decode(File::get($tunnelInfoPath), true);
            
            $this->line("Status: ✅ Active");
            $this->line("Method: {$tunnelInfo['method']}");
            $this->line("URL: {$tunnelInfo['url']}");
            $this->line("Port: {$tunnelInfo['port']}");
            $this->line("Started: {$tunnelInfo['started_at']}");
            
            // Check if webhook is actually set
            $botToken = config('telegram.bot_token') ?? env('TELEGRAM_BOT_TOKEN');
            if ($botToken) {
                $response = Http::get("https://api.telegram.org/bot{$botToken}/getWebhookInfo");
                if ($response->successful()) {
                    $webhookInfo = $response->json()['result'];
                    $this->newLine();
                    $this->line("Telegram Webhook URL: " . ($webhookInfo['url'] ?: 'Not set'));
                    $this->line("Last Error: " . ($webhookInfo['last_error_message'] ?: 'None'));
                    $this->line("Pending Updates: " . $webhookInfo['pending_update_count']);
                }
            }
        } else {
            $this->line("Status: ❌ Not active");
            $this->line("Use 'php artisan dev:webhook start' to begin development testing");
        }
        
        return 0;
    }
    
    private function keepAlive()
    {
        $this->line("\nDevelopment server is running...");
        $this->line("Press Ctrl+C to stop");
        
        // Register signal handler for graceful shutdown
        if (function_exists('pcntl_signal')) {
            pcntl_signal(SIGINT, [$this, 'gracefulShutdown']);
            pcntl_signal(SIGTERM, [$this, 'gracefulShutdown']);
        }
        
        // Keep process alive
        while (true) {
            if (function_exists('pcntl_signal_dispatch')) {
                pcntl_signal_dispatch();
            }
            sleep(1);
        }
    }
    
    public function gracefulShutdown()
    {
        $this->newLine();
        $this->info('Shutting down development webhook...');
        $this->call('dev:webhook', ['action' => 'stop']);
        exit(0);
    }
    
    private function commandExists($command)
    {
        $return = shell_exec(sprintf("which %s 2>/dev/null", escapeshellarg($command)));
        return !empty($return);
    }
}