<?php

namespace App\Http\Controllers\API\v1;

use App\Http\Controllers\Controller;
use App\Events\EmployeeAlertEvent;
use App\Models\Employee;
use App\Models\AlertLog;
use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Validator;
use Pusher\Pusher;

class RealtimeAlertController extends Controller
{
    /**
     * Send real-time alert to employee
     *
     * @param Request $request
     * @return JsonResponse
     */
    public function sendRealtimeAlert(Request $request): JsonResponse
    {
        try {
            // Validate request data
            $validator = Validator::make($request->all(), [
                'employee_id' => 'required|string|exists:employees,employee_id',
                'message' => 'required|string|min:1|max:1000',
                'type' => 'required|string|in:urgent_log_reminder,general_alert,system_notification',
                'employee_data' => 'sometimes|array',
                'employee_data.name' => 'sometimes|string',
                'employee_data.department' => 'sometimes|string',
            ]);

            if ($validator->fails()) {
                return response()->json([
                    'success' => false,
                    'message' => 'Validation failed',
                    'errors' => $validator->errors()
                ], 422);
            }

            $validated = $validator->validated();

            // Find the employee
            $employee = Employee::where('employee_id', $validated['employee_id'])->first();
            
            // Add this to your controller method after the broadcast
            $pusher = new \Pusher\Pusher(
                config('broadcasting.connections.pusher.key'),
                config('broadcasting.connections.pusher.secret'),
                config('broadcasting.connections.pusher.app_id'),
                [
                    'cluster' => config('broadcasting.connections.pusher.options.cluster'),
                    'useTLS' => true,
                ]
            );

            $pusher->trigger('employee.' . $validated['employee_id'], 'test-event', [
                'message' => 'Direct Pusher test'
            ]);

            if (!$employee) {
                return response()->json([
                    'success' => false,
                    'message' => 'Employee not found'
                ], 404);
            }

            // Check if employee has active session
            $hasActiveSession = $this->checkEmployeeActiveSession($employee->employee_id);
            
            if (!$hasActiveSession) {
                return response()->json([
                    'success' => false,
                    'message' => 'Employee is not currently online',
                    'employee' => [
                        'id' => $employee->employee_id,
                        'name' => $employee->fullname
                    ]
                ], 200); // Not an error, just info
            }

            // Check Pusher connectivity before sending
            $pusherStatus = $this->checkPusherConnectivity();
            if (!$pusherStatus['connected']) {
                Log::warning('Pusher connectivity issue detected', $pusherStatus);
            }

            // Prepare alert data
            $alertData = [
                'id' => uniqid('alert_', true),
                'employee_id' => $validated['employee_id'],
                'message' => $validated['message'],
                'type' => $validated['type'],
                'timestamp' => now()->toISOString(),
                'from' => 'System Administrator',
                'employee_data' => $validated['employee_data'] ?? null,
                'priority' => $this->getAlertPriority($validated['type']),
                'requires_acknowledgment' => true
            ];

            // Log the alert attempt
            $this->logAlert($alertData, $employee);

            // Broadcast the event to specific employee via WebSocket/Pusher
            broadcast(new EmployeeAlertEvent($alertData, $employee->employee_id));

            Log::info('Alert broadcast sent', [
                'employee_id' => $validated['employee_id'],
                'channel' => 'employee.' . $validated['employee_id'],
                'alert_id' => $alertData['id'],
                'pusher_connected' => $pusherStatus['connected']
            ]);

            // Also send via Server-Sent Events if configured
            $this->sendViaServerSentEvents($alertData);

            // Optional: Send backup notification (email/SMS) for urgent alerts
            if ($validated['type'] === 'urgent_log_reminder') {
                $this->sendBackupNotification($employee, $alertData);
            }

            return response()->json([
                'success' => true,
                'message' => 'Real-time alert sent successfully',
                'data' => [
                    'alert_id' => $alertData['id'],
                    'employee' => [
                        'id' => $employee->employee_id,
                        'name' => $employee->fullname,
                        'department' => $employee->department_name
                    ],
                    'delivery_status' => 'sent',
                    'delivery_method' => 'websocket',
                    'pusher_connected' => $pusherStatus['connected'],
                    'timestamp' => $alertData['timestamp']
                ]
            ], 200);

        } catch (\Exception $e) {
            Log::error('Real-time alert error: ' . $e->getMessage(), [
                'employee_id' => $request->get('employee_id'),
                'trace' => $e->getTraceAsString()
            ]);

            return response()->json([
                'success' => false,
                'message' => 'Failed to send real-time alert',
                'error' => config('app.debug') ? $e->getMessage() : 'Internal server error'
            ], 500);
        }
    }

    /**
     * Test Pusher WebSocket connection
     */
    public function testPusherConnection(Request $request): JsonResponse
    {
        try {
            // 1. Check configuration
            $configCheck = $this->validatePusherConfig();
            if (!$configCheck['valid']) {
                return response()->json([
                    'success' => false,
                    'message' => 'Pusher configuration is invalid',
                    'errors' => $configCheck['errors']
                ], 500);
            }

            // 2. Test connectivity
            $connectivityCheck = $this->checkPusherConnectivity();
            
            // 3. Send test event
            $testResult = null;
            if ($connectivityCheck['connected']) {
                $testData = [
                    'message' => 'Test message from Laravel',
                    'timestamp' => now()->toISOString(),
                    'test_id' => uniqid('test_', true)
                ];

                $pusher = $this->getPusherInstance();
                $testResult = $pusher->trigger('test-channel', 'test-event', $testData);
            }

            return response()->json([
                'success' => $connectivityCheck['connected'],
                'message' => $connectivityCheck['connected'] ? 'Pusher WebSocket is working' : 'Pusher WebSocket connection failed',
                'data' => [
                    'configuration' => $configCheck,
                    'connectivity' => $connectivityCheck,
                    'test_event_result' => $testResult,
                    'pusher_info' => [
                        'app_id' => config('broadcasting.connections.pusher.app_id'),
                        'cluster' => config('broadcasting.connections.pusher.options.cluster'),
                        'driver' => config('broadcasting.default')
                    ]
                ]
            ]);

        } catch (\Exception $e) {
            Log::error('Pusher test failed', [
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString()
            ]);

            return response()->json([
                'success' => false,
                'message' => 'Pusher test failed',
                'error' => $e->getMessage()
            ], 500);
        }
    }

    /**
     * Get Pusher connection status and channel information (Simplified)
     */
    public function getPusherStatus(): JsonResponse
    {
        try {
            $pusher = $this->getPusherInstance();
            
            // Try different methods based on available SDK version
            $channels = null;
            $method_used = '';
            
            // Try newer method first
            if (method_exists($pusher, 'getChannelsInfo')) {
                $channels = $pusher->getChannelsInfo();
                $method_used = 'getChannelsInfo';
            } 
            // Try older method
            elseif (method_exists($pusher, 'get_channels_info')) {
                $channels = $pusher->get_channels_info();
                $method_used = 'get_channels_info';
            }
            // If neither works, just test connectivity
            else {
                $testResult = $pusher->trigger('status-test', 'ping', ['test' => true]);
                return response()->json([
                    'success' => true,
                    'message' => 'Pusher is working (basic connectivity test)',
                    'data' => [
                        'connection_test' => 'passed',
                        'method_used' => 'trigger_test',
                        'result' => $testResult,
                        'configuration' => [
                            'app_id' => config('broadcasting.connections.pusher.app_id'),
                            'cluster' => config('broadcasting.connections.pusher.options.cluster'),
                            'encrypted' => config('broadcasting.connections.pusher.options.encrypted', true)
                        ]
                    ]
                ]);
            }

            return response()->json([
                'success' => true,
                'data' => [
                    'channels_overview' => $channels,
                    'method_used' => $method_used,
                    'configuration' => [
                        'app_id' => config('broadcasting.connections.pusher.app_id'),
                        'cluster' => config('broadcasting.connections.pusher.options.cluster'),
                        'encrypted' => config('broadcasting.connections.pusher.options.encrypted', true)
                    ]
                ]
            ]);

        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'message' => 'Failed to get Pusher status',
                'error' => $e->getMessage()
            ], 500);
        }
    }

    /**
     * Send test alert to specific employee
     */
    public function sendTestAlert(Request $request): JsonResponse
    {
        $validator = Validator::make($request->all(), [
            'employee_id' => 'required|string|exists:employees,employee_id'
        ]);

        if ($validator->fails()) {
            return response()->json([
                'success' => false,
                'errors' => $validator->errors()
            ], 422);
        }

        try {
            $employee = Employee::where('employee_id', $request->employee_id)->first();
            
            $testAlert = [
                'id' => uniqid('test_alert_', true),
                'employee_id' => $request->employee_id,
                'message' => 'This is a test alert to verify your WebSocket connection is working properly.',
                'type' => 'system_notification',
                'timestamp' => now()->toISOString(),
                'from' => 'System Test',
                'priority' => 'low',
                'is_test' => true
            ];

            // Check Pusher status first
            $pusherStatus = $this->checkPusherConnectivity();
            
            if ($pusherStatus['connected']) {
                // Send via broadcast event
                broadcast(new EmployeeAlertEvent($testAlert, $request->employee_id));
                
                // Also try direct Pusher send
                $pusher = $this->getPusherInstance();
                $directResult = $pusher->trigger(
                    'employee.' . $request->employee_id,
                    'alert.received',
                    $testAlert
                );
                
                return response()->json([
                    'success' => true,
                    'message' => 'Test alert sent successfully',
                    'data' => [
                        'alert_id' => $testAlert['id'],
                        'employee' => [
                            'id' => $employee->employee_id,
                            'name' => $employee->fullname
                        ],
                        'pusher_status' => 'connected',
                        'broadcast_sent' => true,
                        'direct_pusher_result' => $directResult
                    ]
                ]);
            } else {
                return response()->json([
                    'success' => false,
                    'message' => 'Cannot send test alert - Pusher WebSocket not connected',
                    'pusher_error' => $pusherStatus['error'] ?? 'Unknown error'
                ], 503);
            }

        } catch (\Exception $e) {
            Log::error('Test alert failed', [
                'employee_id' => $request->employee_id,
                'error' => $e->getMessage()
            ]);

            return response()->json([
                'success' => false,
                'message' => 'Failed to send test alert',
                'error' => $e->getMessage()
            ], 500);
        }
    }

    /**
     * Check Pusher connectivity (Alternative simple method)
     */
    private function checkPusherConnectivity(): array
    {
        try {
            $pusher = $this->getPusherInstance();
            
            // Simple connectivity test - just try to trigger a test event
            $testData = ['test' => 'connectivity_check', 'timestamp' => time()];
            $result = $pusher->trigger('test-connectivity', 'ping', $testData);
            
            return [
                'connected' => true,
                'method' => 'trigger_test',
                'result' => $result
            ];

        } catch (\Exception $e) {
            return [
                'connected' => false,
                'error' => $e->getMessage(),
                'error_code' => $e->getCode()
            ];
        }
    }

    /**
     * Validate Pusher configuration
     */
    private function validatePusherConfig(): array
    {
        $errors = [];
        
        if (!config('broadcasting.connections.pusher.key')) {
            $errors[] = 'PUSHER_APP_KEY is not configured';
        }
        
        if (!config('broadcasting.connections.pusher.secret')) {
            $errors[] = 'PUSHER_APP_SECRET is not configured';
        }
        
        if (!config('broadcasting.connections.pusher.app_id')) {
            $errors[] = 'PUSHER_APP_ID is not configured';
        }
        
        if (!config('broadcasting.connections.pusher.options.cluster')) {
            $errors[] = 'PUSHER_APP_CLUSTER is not configured';
        }

        if (config('broadcasting.default') !== 'pusher') {
            $errors[] = 'BROADCAST_DRIVER is not set to pusher (current: ' . config('broadcasting.default') . ')';
        }

        return [
            'valid' => empty($errors),
            'errors' => $errors
        ];
    }

    /**
     * Get configured Pusher instance
     */
    private function getPusherInstance(): Pusher
    {
        return new Pusher(
            config('broadcasting.connections.pusher.key'),
            config('broadcasting.connections.pusher.secret'),
            config('broadcasting.connections.pusher.app_id'),
            [
                'cluster' => config('broadcasting.connections.pusher.options.cluster'),
                'useTLS' => config('broadcasting.connections.pusher.options.encrypted', true),
                'timeout' => 10,
                'curl_options' => [
                    CURLOPT_SSL_VERIFYHOST => 0,
                    CURLOPT_SSL_VERIFYPEER => 0,
                ]
            ]
        );
    }

    /**
     * Check if employee has active browser session
     */
    private function checkEmployeeActiveSession(string $employeeId): bool
    {
        // Check active sessions in cache or database
        // This could be Redis, database sessions, or WebSocket connections
        return true;

        // Example using Redis
        if (cache()->has("employee_online_{$employeeId}")) {
            return true;
        }

        // Example checking WebSocket connections
        // You might store active connections in Redis or memory
        return cache()->has("websocket_connection_{$employeeId}");
    }

    /**
     * Get alert priority based on type
     */
    private function getAlertPriority(string $type): string
    {
        $priorities = [
            'urgent_log_reminder' => 'high',
            'general_alert' => 'medium',
            'system_notification' => 'low'
        ];

        return $priorities[$type] ?? 'medium';
    }

    /**
     * Log the alert for audit trail
     */
    private function logAlert(array $alertData, Employee $employee): void
    {
        AlertLog::create([
            'alert_id' => $alertData['id'],
            'employee_id' => $employee->employee_id,
            'message' => $alertData['message'],
            'type' => $alertData['type'],
            'priority' => $alertData['priority'],
            'sent_by' => auth()->user()->id ?? null,
            'sent_at' => now(),
            'status' => 'sent'
        ]);
    }

    /**
     * Send via Server-Sent Events as fallback
     */
    private function sendViaServerSentEvents(array $alertData): void
    {
        // Store in cache for SSE endpoint to pick up
        cache()->put(
            "sse_alert_{$alertData['employee_id']}_{$alertData['id']}", 
            $alertData, 
            300 // 5 minutes
        );
    }

    /**
     * Send backup notification for urgent alerts
     */
    private function sendBackupNotification(Employee $employee, array $alertData): void
    {
        if ($alertData['priority'] === 'high') {
            // Send email notification
            // Mail::to($employee->email)->send(new UrgentAlertMail($alertData));
            
            // Or SMS notification
            // SMS::send($employee->phone, $alertData['message']);
        }
    }

    /**
     * Get employee online status
     */
    public function getEmployeeOnlineStatus(Request $request): JsonResponse
    {
        $employeeId = $request->get('employee_id');
        
        if (!$employeeId) {
            return response()->json([
                'success' => false,
                'message' => 'Employee ID is required'
            ], 400);
        }

        $isOnline = $this->checkEmployeeActiveSession($employeeId);
        $lastSeen = cache()->get("employee_last_seen_{$employeeId}");

        return response()->json([
            'success' => true,
            'data' => [
                'employee_id' => $employeeId,
                'is_online' => $isOnline,
                'last_seen' => $lastSeen,
                'status' => $isOnline ? 'online' : 'offline'
            ]
        ]);
    }

    /**
     * Acknowledge alert receipt
     */
    public function acknowledgeAlert(Request $request): JsonResponse
    {
        $validator = Validator::make($request->all(), [
            'alert_id' => 'required|string',
            'employee_id' => 'required|string'
        ]);

        if ($validator->fails()) {
            return response()->json([
                'success' => false,
                'errors' => $validator->errors()
            ], 422);
        }

        // Update alert log
        AlertLog::where('alert_id', $request->alert_id)
                ->where('employee_id', $request->employee_id)
                ->update([
                    'status' => 'acknowledged',
                    'acknowledged_at' => now()
                ]);

        return response()->json([
            'success' => true,
            'message' => 'Alert acknowledged successfully'
        ]);
    }
}