<?php

namespace App\Modules\ThreeCX\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Response;
use App\Http\Controllers\BaseController;
use App\Models\Setting;
use App\Modules\Bookings\Task;
use App\Models\User;

class ThreeCXController extends BaseController
{
    protected $threeCXService;
    protected $threeCXIntegrationService;

    public function __construct(
        \App\Modules\ThreeCX\Services\ThreeCXIntegrationService $threeCXIntegrationService
    ) {
        $this->threeCXIntegrationService = $threeCXIntegrationService;
    }

    /**
     * Initiate a call from task detail view
     *
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function startCall(Request $request)
    {
        Log::info('[3CX] API startCall method called', [
            'request_data' => $request->all(),
            'user_id' => Auth::id(),
            'url' => $request->url(),
            'method' => $request->method()
        ]);
        
        $request->validate([
            'task_id' => 'nullable|integer|exists:tasks,id',
            'phone_number' => 'required|string',
            'extension' => 'nullable|string',
            'timeout' => 'nullable|integer|min:10|max:60',
            'static_display' => 'nullable|boolean'
        ]);
        
        Log::info('[3CX] Validation passed');

        try {
            // Task is optional (for test calls from admin)
            $task = null;
            if ($request->task_id) {
                $task = Task::find($request->task_id);
                if (!$task) {
                    return Response::json([
                        'success' => false,
                        'message' => 'Task not found'
                    ], 404);
                }
            }

            // Get the appropriate extension based on context
            // If extension is explicitly provided, use it (admin test calls)
            // If no task_id provided, assume admin context and use API extension
            // Otherwise, use user-specific extension for task calls
            if ($request->extension) {
                $extension = $request->extension;
            } elseif (!$request->task_id) {
                // Admin context - use integration settings extension
                $extension = \App\Modules\ThreeCX\Services\ThreeCXExtensionResolver::getExtensionForApiCall();
            } else {
                // Task context - use user-specific extension
                $extension = \App\Modules\ThreeCX\Services\ThreeCXExtensionResolver::getExtensionForUser();
            }
            
            Log::info('[3CX] Using 3CX extension', [
                'requested_extension' => $request->extension,
                'resolved_extension' => $extension,
                'using_extension' => $extension,
                'to_number' => $request->phone_number,
                'task_id' => $request->task_id
            ]);
            
            if (!$extension) {
                return Response::json([
                    'success' => false,
                    'message' => 'No 3CX extension configured. Please configure a default extension in Admin > Settings > Integrations.',
                    'suggestion' => 'An administrator needs to set the 3CX extension that will make outbound calls.'
                ], 400);
            }

            $result = $this->threeCXIntegrationService->makeCall(
                $request->phone_number,
                [
                    'timeout' => $request->timeout ?? 30,
                    'task_id' => $request->task_id,
                    'user_id' => Auth::id(),
                    'extension' => $extension,
                    'static_display' => $request->static_display ?? false
                ]
            );
            
            // Create call log record immediately when call starts (if it's a task call)
            $callLogId = null;
            if ($result['success'] && $request->task_id && $result['participant_id']) {
                $callLogId = $this->createInitialCallLog($request, $extension, $result);
            }

            if ($result['success']) {
                return Response::json([
                    'success' => true,
                    'message' => $result['message'] ?? 'Call initiated successfully',
                    'call_status' => $result['call_status'] ?? 'initiated',
                    'call_events' => $result['call_events'] ?? [],
                    'duration' => $result['duration'] ?? 0,
                    'data' => $result['data'] ?? null,
                    'participant_id' => $result['participant_id'] ?? null,
                    'call_id' => $result['call_id'] ?? null,
                    'call_log_id' => $callLogId,
                    'tracking_started' => $result['tracking_started'] ?? false
                ]);
            } else {
                $statusCode = 400;
                if (isset($result['status_code'])) {
                    $statusCode = $result['status_code'] == 424 ? 424 : 400;
                }
                
                return Response::json([
                    'success' => false,
                    'message' => $result['error'] ?? 'Failed to initiate call',
                    'suggestion' => $result['suggestion'] ?? null,
                    'call_status' => $result['call_status'] ?? 'failed',
                    'call_events' => $result['call_events'] ?? [],
                    'duration' => $result['duration'] ?? 0,
                    'participant_id' => $result['participant_id'] ?? null,
                    'call_id' => $result['call_id'] ?? null,
                    'tracking_started' => $result['tracking_started'] ?? false,
                    'user_friendly' => $result['user_friendly'] ?? false
                ], $statusCode);
            }

        } catch (\Exception $e) {
            return Response::json([
                'success' => false,
                'message' => 'An error occurred while initiating the call: ' . $e->getMessage()
            ], 500);
        }
    }

    /**
     * Stop an active call
     *
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function stopCall(Request $request)
    {
        $request->validate([
            'call_id' => 'required|string'
        ]);

        try {
            // Simplified: hangup via integration service if supported or return not implemented
            return Response::json([
                'success' => false,
                'message' => 'Hangup not supported in simplified flow'
            ], 400);

            if ($result['success']) {
                return Response::json([
                    'success' => true,
                    'message' => 'Call ended successfully'
                ]);
            } else {
                return Response::json([
                    'success' => false,
                    'message' => $result['error'] ?? 'Failed to end call'
                ], 400);
            }

        } catch (\Exception $e) {
            return Response::json([
                'success' => false,
                'message' => 'An error occurred while ending the call: ' . $e->getMessage()
            ], 500);
        }
    }

    /**
     * Sync call status for a specific call (used by static display mode)
     * Updates only the specific call that was made, not all calls in task
     *
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function syncCallStatus(Request $request)
    {
        Log::info('[3CX] Syncing specific call status', [
            'request_data' => $request->all(),
            'user_id' => Auth::id()
        ]);
        
        $request->validate([
            'participant_id' => 'required|string',
            'call_id' => 'nullable|string',
            'final_status' => 'required|string',
            'end_reason' => 'nullable|string',
            'task_id' => 'nullable|integer|exists:tasks,id'
        ]);

        try {
            // First, try to fetch actual call details from 3CX using call_id
            $threeCXCallDetails = null;
            if ($request->call_id) {
                try {
                    Log::info('[3CX] Fetching call details from 3CX API', [
                        'call_id' => $request->call_id,
                        'participant_id' => $request->participant_id
                    ]);
                    
                    // You can implement CallHistoryView API call here
                    // For now, we'll use the provided status but this can be enhanced
                    $threeCXCallDetails = [
                        'call_id' => $request->call_id,
                        'status' => $request->final_status,
                        'reason' => $request->end_reason
                    ];
                } catch (\Exception $e) {
                    Log::warning('[3CX] Failed to fetch call details from 3CX API', [
                        'call_id' => $request->call_id,
                        'error' => $e->getMessage()
                    ]);
                }
            }
            
            // Find the specific call log by participant_id (most recent for this task if task_id provided)
            $query = \App\Modules\ThreeCX\Models\TaskCallLog::where('participant_id', $request->participant_id);
            
            if ($request->task_id) {
                $query->where('task_id', $request->task_id);
            }
            
            $callLog = $query->orderBy('created_at', 'desc')->first();

            if (!$callLog) {
                return Response::json([
                    'success' => false,
                    'message' => 'Call log not found for participant ID: ' . $request->participant_id
                ], 404);
            }

            // Map status to user-friendly status
            $statusMapping = [
                'ended' => 'completed',
                'failed' => 'failed',
                'answered' => 'completed',
                'connected' => 'completed',
                'dialing_reception' => 'initiated',
                'ringing_reception' => 'initiated',
                'dialing_customer' => 'initiated',
                'ringing_customer' => 'initiated'
            ];
            
            $finalStatus = $statusMapping[$request->final_status] ?? $request->final_status;

            // Update the specific call log
            $callLog->status = $finalStatus;
            $callLog->end_reason = $request->end_reason;
            $callLog->ended_at = now();
            
            // Calculate duration if call was connected
            if (in_array($finalStatus, ['completed']) && $callLog->started_at) {
                $callLog->duration = $callLog->started_at->diffInSeconds($callLog->ended_at);
            } else {
                $callLog->duration = 0;
            }
            
            $callLog->save();

            Log::info('[3CX] Successfully synced call status', [
                'call_log_id' => $callLog->id,
                'participant_id' => $request->participant_id,
                'final_status' => $finalStatus,
                'duration' => $callLog->duration
            ]);

            return Response::json([
                'success' => true,
                'message' => 'Call status synchronized successfully',
                'call_log' => [
                    'id' => $callLog->id,
                    'status' => $callLog->status,
                    'duration' => $callLog->duration,
                    'end_reason' => $callLog->end_reason
                ]
            ]);

        } catch (\Exception $e) {
            Log::error('[3CX] Failed to sync call status', [
                'participant_id' => $request->participant_id,
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString()
            ]);

            return Response::json([
                'success' => false,
                'message' => 'Failed to sync call status: ' . $e->getMessage()
            ], 500);
        }
    }

    /**
     * Get call logs for a specific task
     *
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function getTaskCallLogs(Request $request)
    {
        $request->validate([
            'task_id' => 'required|integer|exists:tasks,id'
        ]);

        try {
            $taskId = $request->task_id;
            
            // Get task call logs from TaskCallLog model
            $callLogs = \App\Modules\ThreeCX\Models\TaskCallLog::forTask($taskId)
                ->with(['user:id,first_name,last_name'])
                ->orderBy('called_at', 'desc')
                ->limit(50)
                ->get();

            // Transform the data for frontend consumption
            $logsData = $callLogs->map(function($log) {
                return [
                    'id' => $log->id,
                    'task_id' => $log->task_id,
                    'user_id' => $log->user_id,
                    'user_name' => $log->user ? ($log->user->first_name . ' ' . $log->user->last_name) : 'Unknown',
                    'phone_number' => $log->to_number,
                    'number' => $log->to_number, // For compatibility
                    'extension' => $log->from_extension,
                    'call_id' => $log->call_id,
                    'duration' => $log->duration ?: 0,
                    'status' => $log->status,
                    'state' => $log->status, // For compatibility with both templates
                    'called_at' => $log->called_at->toISOString(),
                    'created_at' => $log->called_at->toISOString(), // For compatibility
                    'answered_at' => $log->answered_at?->toISOString(),
                    'ended_at' => $log->ended_at?->toISOString(),
                    'notes' => $log->notes,
                    'metadata' => $log->metadata
                ];
            });

            return Response::json([
                'success' => true,
                'data' => $logsData,
                'count' => $logsData->count(),
                'task_id' => $taskId
            ]);

        } catch (\Exception $e) {
            Log::error('[3CX] Failed to fetch task call logs', [
                'task_id' => $request->task_id ?? 'unknown',
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString()
            ]);

            return Response::json([
                'success' => false,
                'message' => 'An error occurred while fetching call logs: ' . $e->getMessage()
            ], 500);
        }
    }

    /**
     * Get call logs for the current user
     *
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function getUserCallLogs(Request $request)
    {
        try {
            $userId = $request->user_id ?? Auth::id();
            return Response::json([
                'success' => true,
                'data' => []
            ]);

            if ($result['success']) {
                return Response::json([
                    'success' => true,
                    'data' => $result['data']
                ]);
            } else {
                return Response::json([
                    'success' => false,
                    'message' => $result['error'] ?? 'Failed to fetch call logs'
                ], 400);
            }

        } catch (\Exception $e) {
            return Response::json([
                'success' => false,
                'message' => 'An error occurred while fetching call logs: ' . $e->getMessage()
            ], 500);
        }
    }

    /**
     * Get call status
     *
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function getCallStatus(Request $request, $participantId = null)
    {
        // Handle both URL parameter and request parameter
        $participantId = $participantId ?? $request->participant_id;
        
        if (!$participantId) {
            return Response::json([
                'success' => false,
                'message' => 'Participant ID is required'
            ], 400);
        }

        try {
            $integrationService = app(\App\Modules\ThreeCX\Services\ThreeCXIntegrationService::class);
            $callInfo = $integrationService->getCallStatus($participantId);

            // CRITICAL FIX: Check if this participant has migrated to a new one (even if we have callInfo)
            $cachedInfo = Cache::get("threecx_call_{$participantId}");
            if ($cachedInfo && isset($cachedInfo['migrated_to'])) {
                $newParticipantId = $cachedInfo['migrated_to'];
                Log::info('[3CX Migration] Participant migrated, checking newer status', [
                    'old_participant_id' => $participantId,
                    'new_participant_id' => $newParticipantId,
                    'has_old_callinfo' => !is_null($callInfo)
                ]);
                
                // Get status for the new participant (this might have more recent status)
                $newCallInfo = $integrationService->getCallStatus($newParticipantId);
                if ($newCallInfo) {
                    // Use the newer participant's status
                    $callInfo = $newCallInfo;
                    $callInfo['participant_id'] = $newParticipantId;
                    $callInfo['original_participant_id'] = $participantId;
                    $callInfo['migrated'] = true;
                    
                    Log::info('[3CX Migration] Using migrated participant status', [
                        'old_participant_id' => $participantId,
                        'new_participant_id' => $newParticipantId,
                        'new_status' => $callInfo['status']
                    ]);
                } else if (!$callInfo) {
                    // Fallback: if no callInfo for either participant, return migration info
                    Log::warning('[3CX Migration] No status found for either participant', [
                        'old_participant_id' => $participantId,
                        'new_participant_id' => $newParticipantId
                    ]);
                }
            }

            if ($callInfo) {
                $status = strtolower($callInfo['status']);
                
                // Note: Auto-logging is now handled by WebSocket graceful shutdown
                // to avoid race conditions during participant migration
                
                return Response::json([
                    'success' => true,
                    'data' => [
                        'status' => $status,
                        'participant_id' => $callInfo['participant_id'],
                        'call_id' => $callInfo['call_id'],
                        'phone_number' => $callInfo['phone_number'],
                        'started_at' => $callInfo['started_at'],
                        'last_update' => $callInfo['last_update'],
                        'event_data' => $callInfo['event_data'] ?? null
                    ]
                ]);
            } else {
                // Call not found - check if participant has migrated to a newer ID
                $migrationInfo = $this->checkForParticipantMigration($participantId);
                
                if ($migrationInfo) {
                    // Found newer participant - redirect frontend to poll the new one
                    return Response::json([
                        'success' => true,
                        'participant_migrated' => true,
                        'new_participant_id' => $migrationInfo['new_participant_id'],
                        'message' => "Participant migrated from {$participantId} to {$migrationInfo['new_participant_id']}",
                        'data' => [
                            'status' => $migrationInfo['status'],
                            'participant_id' => $migrationInfo['new_participant_id'],
                            'call_id' => $migrationInfo['call_id'],
                            'phone_number' => $migrationInfo['phone_number'],
                            'started_at' => $migrationInfo['started_at'],
                            'last_update' => $migrationInfo['last_update'],
                            'event_data' => $migrationInfo['event_data'] ?? null
                        ]
                    ]);
                } else {
                    // No migration found - call truly ended
                    return Response::json([
                        'success' => false,
                        'message' => 'Call status not found or call has ended',
                        'data' => ['status' => 'ended']
                    ], 404);
                }
            }

        } catch (\Exception $e) {
            return Response::json([
                'success' => false,
                'message' => 'An error occurred while getting call status: ' . $e->getMessage()
            ], 500);
        }
    }

    /**
     * Automatically log call history when a call ends (server-side)
     * This is called when call status polling detects a call has ended
     *
     * @param int $participantId
     * @return void
     */
    private function autoLogCallHistoryOnEnd(int $participantId)
    {
        try {
            // Get call tracking data from cache to find call log ID
            $cacheKey = "threecx_call_tracking_{$participantId}";
            $trackingData = \Cache::get($cacheKey);
            
            // Check if we have a call_log_id to update
            $callLogId = $trackingData['call_log_id'] ?? null;
            
            // If no call_log_id found for this participant, try alternative approaches
            if (!$callLogId) {
                Log::info('[3CX] No call log ID found for participant ' . $participantId . ' - trying alternative lookup');
                
                // Strategy 1: Check for nearby participant IDs that might have the call_log_id
                for ($i = 0; $i < 10; $i++) {
                    $recentParticipantKey = "threecx_call_tracking_" . ($participantId - $i);
                    $recentData = \Cache::get($recentParticipantKey);
                    if ($recentData && !empty($recentData['call_log_id'])) {
                        Log::info('[3CX] Found call log ID from nearby participant', [
                            'ended_participant' => $participantId,
                            'source_participant' => ($participantId - $i),
                            'call_log_id' => $recentData['call_log_id']
                        ]);
                        $callLogId = $recentData['call_log_id'];
                        $trackingData = $recentData;
                        break;
                    }
                }
                
                if (!$callLogId) {
                    Log::info('[3CX] No call log ID found for participant ' . $participantId . ' - skipping update');
                    return;
                }
            }

            // Find the existing call log record to update
            $callHistory = \App\Modules\ThreeCX\Models\TaskCallLog::find($callLogId);
            
            if (!$callHistory) {
                Log::warning('[3CX] Call log record not found for ID: ' . $callLogId);
                return;
            }

            // Calculate call duration
            // Calculate actual customer connected duration (answered to ended), not total call time
            $duration = 0;
            if ($callHistory->answered_at && $finalStatus === 'completed') {
                // Only count duration if customer actually answered the call
                $duration = $callHistory->answered_at->diffInSeconds(now());
            }

            // Check for WebSocket data from newer participants that might indicate answered status
            $wasAnswered = false;
            $answeredTime = null;
            
            // Look for Connected status in recent cache entries (participant ID might have changed)
            for ($i = 1; $i <= 10; $i++) {
                $checkParticipant = $participantId + $i;
                $recentCacheKey = "threecx_call_{$checkParticipant}";
                $recentData = \Cache::get($recentCacheKey, []);
                
                if (!empty($recentData['status']) && in_array($recentData['status'], ['Connected', 'answered'])) {
                    $wasAnswered = true;
                    $answeredTime = now();
                    Log::info('[3CX] Found answered status in newer participant', [
                        'original_participant' => $participantId,
                        'answered_participant' => $checkParticipant,
                        'status' => $recentData['status']
                    ]);
                    // Override tracking data with answered status
                    $trackingData['status'] = 'answered';
                    $trackingData['answered_at'] = $answeredTime->toISOString();
                    break;
                }
            }
            
            // Determine the final call status based on tracking data
            $finalStatus = 'completed'; // Default
            
            Log::info('[3CX] Determining final status from tracking data', [
                'participant_id' => $participantId,
                'tracking_data' => $trackingData,
                'was_answered' => $wasAnswered
            ]);
            
            if (isset($trackingData['status'])) {
                switch ($trackingData['status']) {
                    case 'ended':
                        // Check rejection reason from tracking data
                        if (isset($trackingData['rejection_reason'])) {
                            switch ($trackingData['rejection_reason']) {
                                case 'reception_rejected':
                                    $finalStatus = 'failed'; // Map reception rejected to failed
                                    break;
                                case 'call_completed':
                                    $finalStatus = 'completed';
                                    break;
                                default:
                                    $finalStatus = 'failed';
                            }
                        } else {
                            $finalStatus = 'completed'; // Generic ended status maps to completed
                        }
                        break;
                    case 'answered':
                    case 'connected':
                        $finalStatus = 'answered';
                        break;
                    case 'failed':
                    case 'error':
                        $finalStatus = 'failed';
                        break;
                    case 'cancelled':
                        $finalStatus = 'cancelled';
                        break;
                    default:
                        $finalStatus = 'completed';
                }
            }

            // Update the call history record with final data
            $updateData = [
                'duration' => $duration,
                'status' => $finalStatus,
                'ended_at' => now(),
                'metadata' => array_merge($callHistory->metadata ?? [], [
                    'ended_participant_id' => $participantId,
                    'source' => 'updated_on_end',
                    'participant_switched' => $participantId != ($callHistory->metadata['participant_id'] ?? $participantId),
                    'final_tracking_data' => $trackingData,
                    'final_status_determined' => $finalStatus,
                    'was_answered' => $wasAnswered
                ])
            ];
            
            // Set answered_at if the call was answered (from WebSocket tracking data)
            if ($wasAnswered && $answeredTime) {
                $updateData['answered_at'] = $answeredTime;
            } else if ($finalStatus === 'completed' && !$callHistory->answered_at) {
                // If no answered_at time from WebSocket but call completed, estimate it 
                // This handles cases where WebSocket tracking missed the answered event
                $updateData['answered_at'] = $callHistory->called_at->addSeconds(3); // Assume 3 second ring time
            }
            
            $callHistory->update($updateData);

            Log::info('[3CX] Updated call history on call end', [
                'call_history_id' => $callHistory->id,
                'task_id' => $callHistory->task_id,
                'participant_id' => $participantId,
                'duration' => $duration,
                'final_status' => $finalStatus,
                'original_status' => 'initiated',
                'participant_switched' => $participantId != ($callHistory->metadata['participant_id'] ?? $participantId)
            ]);

            // Clean up tracking cache after successful update
            \Cache::forget($cacheKey);

        } catch (\Exception $e) {
            Log::error('[3CX] Failed to auto-log call history on server side', [
                'participant_id' => $participantId,
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString()
            ]);
        }
    }

    /**
     * Manually sync CDR logs (admin function)
     *
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function syncCDR(Request $request)
    {
        try {
            return Response::json([
                'success' => true,
                'message' => 'CDR sync not applicable in simplified flow',
                'synced_count' => 0
            ]);

            if ($result['success']) {
                return Response::json([
                    'success' => true,
                    'message' => $result['message'],
                    'synced_count' => $result['synced_count']
                ]);
            } else {
                return Response::json([
                    'success' => false,
                    'message' => $result['error'] ?? 'Failed to sync CDR logs'
                ], 400);
            }

        } catch (\Exception $e) {
            return Response::json([
                'success' => false,
                'message' => 'An error occurred while syncing CDR logs: ' . $e->getMessage()
            ], 500);
        }
    }

    /**
     * Test 3CX connection (admin function)
     *
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function testConnection(Request $request)
    {
        try {
            $result = app(\App\Modules\ThreeCX\Services\ThreeCXAuthService::class)->testConnection();

            return Response::json([
                'success' => $result['success'],
                'message' => $result['message']
            ], $result['success'] ? 200 : 400);

        } catch (\Exception $e) {
            return Response::json([
                'success' => false,
                'message' => 'An error occurred while testing connection: ' . $e->getMessage()
            ], 500);
        }
    }

    /**
     * Get task data (alternative endpoint for task detail auth compatibility)
     *
     * @param int $id
     * @return \Illuminate\Http\JsonResponse
     */
    public function getTaskData($id)
    {
        try {
            // Use the same logic as TaskControllerREST@show but with simpler auth
            $taskController = new \App\Modules\Bookings\TaskControllerREST(
                app(\App\Modules\Bookings\TaskRepositoryInterface::class)
            );
            
            // Create a request object for the task controller
            $request = new Request(['id' => $id]);
            
            // Call the original show method
            $response = $taskController->show($id, $request);
            
            // Return the same data but through our auth-compatible endpoint
            return $response;
            
        } catch (\Exception $e) {
            return Response::json([
                'success' => false,
                'message' => 'An error occurred while fetching task data: ' . $e->getMessage()
            ], 500);
        }
    }

    /**
     * Admin Integration Test Call (admin only)
     * Same logic as startCall but specifically for admin integrations page
     *
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function adminTestCall(Request $request)
    {
        Log::info('[3CX] Admin test call method called', [
            'request_data' => $request->all(),
            'user_id' => Auth::id(),
            'url' => $request->url(),
            'method' => $request->method()
        ]);
        
        $request->validate([
            'phone_number' => 'required|string',
            'extension' => 'nullable|string',
            'timeout' => 'nullable|integer|min:10|max:60'
        ]);
        
        Log::info('[3CX] Admin test validation passed');

        try {
            // For admin test calls, always use the integration settings extension (or provided override)
            $extension = $request->extension ?? \App\Modules\ThreeCX\Services\ThreeCXExtensionResolver::getExtensionForApiCall();
            
            Log::info('[3CX] Admin test using 3CX extension', [
                'requested_extension' => $request->extension,
                'resolved_extension' => $extension,
                'using_extension' => $extension,
                'to_number' => $request->phone_number
            ]);
            
            if (!$extension) {
                return Response::json([
                    'success' => false,
                    'message' => 'No 3CX extension configured. Please configure a default extension in Admin > Settings > Integrations.',
                    'suggestion' => 'An administrator needs to set the 3CX extension that will make outbound calls.'
                ], 400);
            }

            $result = $this->threeCXIntegrationService->makeCall(
                $request->phone_number,
                ['timeout' => $request->timeout ?? 30]
            );

            if ($result['success']) {
                return Response::json([
                    'success' => true,
                    'message' => $result['message'] ?? 'Call initiated successfully',
                    'call_status' => $result['call_status'] ?? 'initiated',
                    'call_events' => $result['call_events'] ?? [],
                    'duration' => $result['duration'] ?? 0,
                    'data' => $result['data'] ?? null,
                    'participant_id' => $result['participant_id'] ?? null,
                    'call_id' => $result['call_id'] ?? null,
                    'tracking_started' => $result['tracking_started'] ?? false
                ]);
            } else {
                $statusCode = 400;
                if (isset($result['status_code'])) {
                    $statusCode = $result['status_code'] == 424 ? 424 : 400;
                }
                
                return Response::json([
                    'success' => false,
                    'message' => $result['error'] ?? 'Failed to initiate call',
                    'suggestion' => $result['suggestion'] ?? null,
                    'call_status' => $result['call_status'] ?? 'failed',
                    'call_events' => $result['call_events'] ?? [],
                    'duration' => $result['duration'] ?? 0,
                    'participant_id' => $result['participant_id'] ?? null,
                    'call_id' => $result['call_id'] ?? null,
                    'tracking_started' => $result['tracking_started'] ?? false,
                    'user_friendly' => $result['user_friendly'] ?? false
                ], $statusCode);
            }

        } catch (\Exception $e) {
            return Response::json([
                'success' => false,
                'message' => 'An error occurred while initiating the test call: ' . $e->getMessage()
            ], 500);
        }
    }

    /**
     * Admin Integration Hangup Call (admin only)
     * Same logic as stopCall but specifically for admin integrations page
     *
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function adminHangupCall(Request $request)
    {
        $request->validate([
            'participant_id' => 'required|integer'
        ]);

        try {
            // Use the integration service to hang up the call by participant ID
            $integrationService = app(\App\Modules\ThreeCX\Services\ThreeCXIntegrationService::class);
            $result = $integrationService->hangUpCallByParticipant($request->participant_id);

            if ($result['success']) {
                return Response::json([
                    'success' => true,
                    'message' => 'Call ended successfully'
                ]);
            } else {
                return Response::json([
                    'success' => false,
                    'message' => $result['error'] ?? 'Failed to end call'
                ], 400);
            }

        } catch (\Exception $e) {
            return Response::json([
                'success' => false,
                'message' => 'An error occurred while ending the call: ' . $e->getMessage()
            ], 500);
        }
    }

    /**
     * Log call history for task-related calls
     *
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function logCallHistory(Request $request)
    {
        Log::info('[3CX] Call history logging requested', [
            'request_data' => $request->all(),
            'user_id' => Auth::id()
        ]);

        $request->validate([
            'task_id' => 'required|integer|exists:tasks,id',
            'phone_number' => 'required|string',
            'extension' => 'required|string',
            'duration' => 'nullable|integer',
            'status' => 'required|string',
            'call_id' => 'nullable|string',
            'participant_id' => 'nullable|string'
        ]);

        try {
            $task = Task::find($request->task_id);
            if (!$task) {
                return Response::json([
                    'success' => false,
                    'message' => 'Task not found'
                ], 404);
            }

            // Create call history record using TaskCallLog model
            $callHistory = new \App\Modules\ThreeCX\Models\TaskCallLog([
                'task_id' => $request->task_id,
                'user_id' => Auth::id(),
                'to_number' => $request->phone_number,
                'from_extension' => $request->extension,
                'duration' => $request->duration ?? 0,
                'status' => $request->status,
                'call_id' => $request->call_id,
                'called_at' => now(),
                'metadata' => [
                    'participant_id' => $request->participant_id,
                    'source' => 'task_widget'
                ]
            ]);

            $callHistory->save();

            Log::info('[3CX] Call history logged successfully', [
                'call_history_id' => $callHistory->id,
                'task_id' => $request->task_id,
                'phone_number' => $request->phone_number
            ]);

            return Response::json([
                'success' => true,
                'message' => 'Call history logged successfully',
                'call_history_id' => $callHistory->id
            ]);

        } catch (\Exception $e) {
            Log::error('[3CX] Failed to log call history', [
                'error' => $e->getMessage(),
                'task_id' => $request->task_id,
                'phone_number' => $request->phone_number
            ]);

            return Response::json([
                'success' => false,
                'message' => 'Failed to log call history: ' . $e->getMessage()
            ], 500);
        }
    }

    /**
     * Public method to trigger call history update when call ends
     * Called from IntegrationsController when call end is detected
     *
     * @param int $participantId
     * @return void
     */
    public function triggerCallHistoryUpdate(int $participantId)
    {
        $this->autoLogCallHistoryOnEnd($participantId);
    }

    /**
     * Finalize all pending call logs for a task
     * Called by WebSocket when all calls for a task have ended
     *
     * @param int $taskId
     * @return \Illuminate\Http\JsonResponse
     */
    public function finalizeTaskCallLogs(int $taskId)
    {
        try {
            Log::info('[3CX] Finalizing call logs for task', ['task_id' => $taskId]);

            // Find all call logs for this task that are still in 'initiated' status
            $pendingCallLogs = \App\Modules\ThreeCX\Models\TaskCallLog::where('task_id', $taskId)
                ->where('status', 'initiated')
                ->get();

            if ($pendingCallLogs->isEmpty()) {
                Log::info('[3CX] No pending call logs found for task', ['task_id' => $taskId]);
                return response()->json([
                    'success' => true,
                    'message' => 'No pending call logs to finalize',
                    'updated_count' => 0
                ]);
            }

            $updatedCount = 0;
            foreach ($pendingCallLogs as $callLog) {
                $participantId = $callLog->metadata['participant_id'] ?? null;
                if (!$participantId) {
                    Log::warning('[3CX] Call log missing participant_id', ['call_log_id' => $callLog->id]);
                    continue;
                }

                // Get the final status from cache (WebSocket data)
                $finalStatus = 'completed'; // Default
                $answeredAt = null;
                
                // Check WebSocket cache for final status
                for ($i = 0; $i <= 5; $i++) {
                    $checkParticipant = $participantId + $i;
                    $webSocketData = \Cache::get("threecx_call_{$checkParticipant}");
                    
                    if ($webSocketData && !empty($webSocketData['status'])) {
                        // Determine final status from WebSocket data
                        if (in_array($webSocketData['status'], ['Connected', 'answered'])) {
                            $finalStatus = 'answered';
                            $answeredAt = now();
                        } elseif (in_array($webSocketData['status'], ['ended']) && !empty($webSocketData['rejection_reason'])) {
                            $finalStatus = ($webSocketData['rejection_reason'] === 'reception_rejected' || 
                                          $webSocketData['rejection_reason'] === 'customer_rejected') ? 'failed' : 'completed';
                        } elseif (in_array($webSocketData['status'], ['failed', 'rejected'])) {
                            $finalStatus = 'failed';
                        }
                        
                        Log::info('[3CX] Found WebSocket data for finalization', [
                            'call_log_id' => $callLog->id,
                            'participant_id' => $checkParticipant,
                            'websocket_status' => $webSocketData['status'],
                            'final_status' => $finalStatus
                        ]);
                        break;
                    }
                }

                // Calculate duration
                // Calculate actual customer connected duration (answered to ended), not total call time  
                $duration = 0;
                if ($callLog->answered_at && $finalStatus === 'completed') {
                    // Only count duration if customer actually answered the call
                    $duration = $callLog->answered_at->diffInSeconds(now());
                }

                // Update the call log
                $updateData = [
                    'status' => $finalStatus,
                    'duration' => $duration,
                    'ended_at' => now(),
                    'metadata' => array_merge($callLog->metadata ?? [], [
                        'finalized_by' => 'websocket_shutdown',
                        'final_status_determined' => $finalStatus,
                        'finalized_at' => now()->toISOString()
                    ])
                ];

                if ($answeredAt) {
                    $updateData['answered_at'] = $answeredAt;
                } else if ($finalStatus === 'completed' && !$callLog->answered_at) {
                    // If no answered_at time from WebSocket but call completed, estimate it
                    $updateData['answered_at'] = $callLog->called_at->addSeconds(3); // Assume 3 second ring time
                }

                $callLog->update($updateData);
                $updatedCount++;

                Log::info('[3CX] Finalized call log', [
                    'call_log_id' => $callLog->id,
                    'task_id' => $taskId,
                    'final_status' => $finalStatus,
                    'duration' => $duration
                ]);
            }

            return response()->json([
                'success' => true,
                'message' => "Finalized {$updatedCount} call logs",
                'updated_count' => $updatedCount
            ]);

        } catch (\Exception $e) {
            Log::error('[3CX] Error finalizing task call logs', [
                'task_id' => $taskId,
                'error' => $e->getMessage()
            ]);

            return response()->json([
                'success' => false,
                'message' => 'Error finalizing call logs: ' . $e->getMessage()
            ], 500);
        }
    }

    /**
     * Create initial call log record when call starts
     *
     * @param Request $request
     * @param string $extension
     * @param array $result
     * @return int|null
     */
    private function createInitialCallLog($request, $extension, $result)
    {
        try {
            $callHistory = new \App\Modules\ThreeCX\Models\TaskCallLog([
                'task_id' => $request->task_id,
                'user_id' => Auth::id(),
                'to_number' => $request->phone_number,
                'from_extension' => $extension,
                'duration' => 0, // Will be updated when call ends
                'status' => 'initiated', // Will be updated when call ends
                'call_id' => $result['call_id'],
                'called_at' => now(),
                'answered_at' => null, // Will be updated if answered
                'ended_at' => null, // Will be updated when call ends
                'metadata' => [
                    'participant_id' => $result['participant_id'],
                    'source' => 'early_logging_on_start',
                    'timeout' => $request->timeout ?? 30,
                    'initial_call_data' => $result
                ]
            ]);
            
            $callHistory->save();
            $callLogId = $callHistory->id;
            
            Log::info('[3CX] Created call log record on call start', [
                'call_log_id' => $callLogId,
                'task_id' => $request->task_id,
                'participant_id' => $result['participant_id'],
                'call_id' => $result['call_id']
            ]);
            
            // Store the call log ID in the tracking cache for later updates
            $trackingCacheKey = "threecx_call_tracking_" . $result['participant_id'];
            $existingCache = \Cache::get($trackingCacheKey, []);
            $existingCache['call_log_id'] = $callLogId;
            \Cache::put($trackingCacheKey, $existingCache, now()->addMinutes(30));
            
            return $callLogId;
            
        } catch (\Exception $e) {
            Log::error('[3CX] Failed to create initial call log', [
                'error' => $e->getMessage(),
                'task_id' => $request->task_id,
                'participant_id' => $result['participant_id']
            ]);
            return null;
        }
    }

    /**
     * Get the final/current participant ID after potential WebSocket migration
     */
    private function getFinalParticipantId($originalParticipantId, $callId)
    {
        try {
            // First check if original participant still exists
            $originalCache = Cache::get("threecx_call_{$originalParticipantId}");
            if ($originalCache) {
                Log::info('[3CX] Original participant still active', ['participant_id' => $originalParticipantId]);
                return $originalParticipantId;
            }
            
            // Check active calls for the same real call ID
            $activeCalls = Cache::get('threecx_active_calls', []);
            foreach ($activeCalls as $activeParticipantId) {
                $activeCallInfo = Cache::get("threecx_call_{$activeParticipantId}");
                if ($activeCallInfo && 
                    isset($activeCallInfo['event_data']['callid']) && 
                    $activeCallInfo['event_data']['callid'] == $callId) {
                    
                    Log::info('[3CX] Found migrated participant at call start', [
                        'original_participant_id' => $originalParticipantId,
                        'final_participant_id' => $activeParticipantId,
                        'call_id' => $callId
                    ]);
                    
                    return $activeParticipantId;
                }
            }
            
            Log::info('[3CX] No migration detected, using original participant', ['participant_id' => $originalParticipantId]);
            return $originalParticipantId;
            
        } catch (\Exception $e) {
            Log::error('[3CX] Error checking final participant ID', [
                'original_participant_id' => $originalParticipantId,
                'error' => $e->getMessage()
            ]);
            return $originalParticipantId;
        }
    }

    /**
     * Check if a participant has migrated to a newer participant ID for the same call
     */
    private function checkForParticipantMigration($oldParticipantId)
    {
        try {
            // Get the original call info from cache to find the real call ID
            $originalCallInfo = Cache::get("threecx_call_{$oldParticipantId}");
            if (!$originalCallInfo || !isset($originalCallInfo['event_data']['callid'])) {
                return null;
            }
            
            $realCallId = $originalCallInfo['event_data']['callid'];
            Log::info('[3CX Migration Check] Looking for newer participant', [
                'old_participant_id' => $oldParticipantId, 
                'real_call_id' => $realCallId
            ]);
            
            // Check all active calls for the same real call ID
            $activeCalls = Cache::get('threecx_active_calls', []);
            foreach ($activeCalls as $activeParticipantId) {
                if ($activeParticipantId == $oldParticipantId) continue; // Skip the old one
                
                $activeCallInfo = Cache::get("threecx_call_{$activeParticipantId}");
                if ($activeCallInfo && 
                    isset($activeCallInfo['event_data']['callid']) && 
                    $activeCallInfo['event_data']['callid'] == $realCallId) {
                    
                    Log::info('[3CX Migration Check] Found newer participant', [
                        'old_participant_id' => $oldParticipantId,
                        'new_participant_id' => $activeParticipantId,
                        'real_call_id' => $realCallId
                    ]);
                    
                    return [
                        'new_participant_id' => $activeParticipantId,
                        'status' => $activeCallInfo['status'],
                        'call_id' => $activeCallInfo['call_id'],
                        'phone_number' => $activeCallInfo['phone_number'],
                        'started_at' => $activeCallInfo['started_at'],
                        'last_update' => $activeCallInfo['last_update'],
                        'event_data' => $activeCallInfo['event_data'] ?? null
                    ];
                }
            }
            
            Log::info('[3CX Migration Check] No newer participant found', [
                'old_participant_id' => $oldParticipantId,
                'real_call_id' => $realCallId,
                'checked_participants' => count($activeCalls)
            ]);
            
            return null;
            
        } catch (\Exception $e) {
            Log::error('[3CX Migration Check] Error checking migration', [
                'old_participant_id' => $oldParticipantId,
                'error' => $e->getMessage()
            ]);
            return null;
        }
    }
}
