<?php

namespace App\Modules\ThreeCX\Services;

use App\Modules\ThreeCX\Services\ThreeCXAuthService;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Cache;
use App\Models\Setting;
use Exception;

/**
 * 3CX Make Call Service
 * 
 * Service for making outbound calls using configurable extension
 * Based on successful manual testing with HTTP POST to callcontrol API
 */
class ThreeCXMakeCallService
{
    protected $authService;
    protected $baseUrl;
    protected $clientExtension;

    public function __construct(ThreeCXAuthService $authService)
    {
        $this->authService = $authService;
        $this->baseUrl = Setting::get('integrations.threecx.base_url', '');
        // Use extension resolver to get appropriate extension for current user
        $this->clientExtension = \App\Modules\ThreeCX\Services\ThreeCXExtensionResolver::getExtensionForUser();
    }

    /**
     * Initiate a click-to-call to external number
     * 
     * @param string $phoneNumber The customer phone number to call
     * @param int $timeout Call timeout in seconds (0 = no timeout)
     * @param string|null $extension Optional extension override (if null, uses default)
     * @return array Result with success status and details
     */
    public function makeCall(string $phoneNumber, int $timeout = 30, ?string $extension = null): array
    {
        try {
            // Use provided extension or fall back to default
            $callExtension = $extension ?? $this->clientExtension;
            
            Log::info('[3CX ClickToCall] Initiating call', [
                'phone_number' => $phoneNumber,
                'timeout' => $timeout,
                'extension' => $callExtension,
                'extension_source' => $extension ? 'parameter' : 'default'
            ]);

            // Get OAuth token
            $token = $this->authService->getToken();
            
            // Prepare the call request
            $callUrl = rtrim($this->baseUrl, '/') . "/callcontrol/{$callExtension}/makecall";
            
            $callData = [
                'destination' => $phoneNumber,
                'timeout' => $timeout
            ];

            Log::info('[3CX ClickToCall] Making call request', [
                'url' => $callUrl,
                'data' => $callData
            ]);

            // Make HTTP POST request to initiate call
            $response = Http::withToken($token)
                ->withOptions(['verify' => false]) // For self-signed certificates
                ->timeout(Setting::get('integrations.threecx.timeout', 30))
                ->accept('application/json')
                ->post($callUrl, $callData);

            if ($response->successful()) {
                $responseData = $response->json();
                
                Log::info('[3CX ClickToCall] Call initiated successfully', [
                    'response' => $responseData
                ]);

                // Extract participant information for tracking from actual response format
                $participantId = null;
                $callId = null;
                
                // Response format: {"finalstatus":"Success","result":{"id":3863,"callid":633,...}}
                // BUT 3CX often returns "result": null, so we need to fetch participant data separately
                if (isset($responseData['result']) && $responseData['result'] !== null) {
                    $result = $responseData['result'];
                    $participantId = $result['id'] ?? null;  // This is the participant ID
                    $callId = $result['callid'] ?? null;     // This is the call ID
                    
                    Log::info('[3CX ClickToCall] Extracted call tracking info from makecall response', [
                        'participant_id' => $participantId,
                        'call_id' => $callId,
                        'status' => $result['status'] ?? 'unknown'
                    ]);
                } else {
                    // makecall response didn't include participant data - fetch from callcontrol
                    Log::info('[3CX ClickToCall] makecall response has null result, fetching participant from callcontrol');
                    
                    try {
                        // Wait a moment for call to be registered in the system
                        usleep(500000); // 0.5 seconds
                        
                        // Fetch current extension status to find the new participant
                        $statusUrl = rtrim($this->baseUrl, '/') . "/callcontrol/";
                        $statusResponse = Http::withToken($token)
                            ->withOptions(['verify' => false])
                            ->timeout(Setting::get('integrations.threecx.timeout', 30))
                            ->accept('application/json')
                            ->get($statusUrl);
                            
                        if ($statusResponse->successful()) {
                            $extensionsData = $statusResponse->json();
                            
                            // Find our extension in the response
                            foreach ($extensionsData as $extensionData) {
                                if ($extensionData['dn'] === $callExtension && !empty($extensionData['participants'])) {
                                    // Find the most recent participant (highest ID or most recent status)
                                    $participants = $extensionData['participants'];
                                    $latestParticipant = null;
                                    $highestId = 0;
                                    
                                    foreach ($participants as $participant) {
                                        $partId = $participant['id'] ?? 0;
                                        if ($partId > $highestId) {
                                            $highestId = $partId;
                                            $latestParticipant = $participant;
                                        }
                                    }
                                    
                                    if ($latestParticipant) {
                                        $participantId = $latestParticipant['id'] ?? null;
                                        $callId = $latestParticipant['callid'] ?? null;
                                        
                                        Log::info('[3CX ClickToCall] Extracted call tracking info from callcontrol', [
                                            'participant_id' => $participantId,
                                            'call_id' => $callId,
                                            'status' => $latestParticipant['status'] ?? 'unknown',
                                            'party_caller_id' => $latestParticipant['party_caller_id'] ?? null
                                        ]);
                                        break;
                                    }
                                }
                            }
                        } else {
                            Log::warning('[3CX ClickToCall] Failed to fetch participant data from callcontrol', [
                                'status' => $statusResponse->status(),
                                'body' => $statusResponse->body()
                            ]);
                        }
                    } catch (Exception $e) {
                        Log::error('[3CX ClickToCall] Exception while fetching participant data', [
                            'error' => $e->getMessage()
                        ]);
                    }
                }

                return [
                    'success' => true,
                    'message' => 'Call initiated successfully',
                    'phone_number' => $phoneNumber,
                    'participant_id' => $participantId,
                    'call_id' => $callId,
                    'extension' => $callExtension,
                    'raw_response' => $responseData
                ];
                
            } else {
                $errorMessage = $response->body();
                $statusCode = $response->status();
                
                Log::error('[3CX ClickToCall] Call request failed', [
                    'status' => $statusCode,
                    'error' => $errorMessage,
                    'extension' => $this->clientExtension,
                    'phone_number' => $phoneNumber
                ]);

                // Provide specific error messages for common HTTP status codes
                $userMessage = match($statusCode) {
                    403 => "Extension {$this->clientExtension} does not have permission to make calls. Please check your extension has permission to call or add extension to API permission list.",
                    401 => "Authentication failed. Please check your 3CX API credentials.",
                    404 => "Extension {$this->clientExtension} not found in 3CX system.",
                    400 => "Invalid call request. Please check the phone number format.",
                    500 => "3CX server error. Please try again later or contact support.",
                    default => "Call request failed with HTTP {$statusCode}. Please contact support."
                };

                return [
                    'success' => false,
                    'error' => 'Call request failed',
                    'message' => $userMessage,
                    'status_code' => $statusCode,
                    'extension_used' => $this->clientExtension,
                    'phone_number' => $phoneNumber
                ];
            }
            
        } catch (Exception $e) {
            Log::error('[3CX ClickToCall] Exception during call', [
                'error' => $e->getMessage(),
                'phone_number' => $phoneNumber,
                'trace' => $e->getTraceAsString()
            ]);

            return [
                'success' => false,
                'error' => 'Exception occurred',
                'message' => $e->getMessage(),
                'phone_number' => $phoneNumber
            ];
        }
    }

    /**
     * Get call status by participant ID
     * 
     * @param string $participantId The participant ID from the call initiation
     * @return array Call status information
     */
    public function getCallStatus(string $participantId): array
    {
        try {
            // Always get a fresh token to prevent 401 errors
            $token = $this->authService->getToken();
            
            if (!$token) {
                return [
                    'success' => false,
                    'error' => 'Failed to get authentication token',
                    'participant_id' => $participantId
                ];
            }
            
            // First, try the participant-specific endpoint
            $statusUrl = rtrim($this->baseUrl, '/') . "/callcontrol/{$this->clientExtension}/participants/{$participantId}";
            
            $response = Http::withToken($token)
                ->withOptions(['verify' => false])
                ->timeout(Setting::get('integrations.threecx.timeout', 30))
                ->accept('application/json')
                ->get($statusUrl);

            if ($response->successful()) {
                $statusData = $response->json();
                
                return [
                    'success' => true,
                    'http_status' => $response->status(),
                    'participant_id' => $participantId,
                    'status' => $statusData,
                    'source' => 'participant_endpoint'
                ];
            } else {
                // If participant endpoint fails, try to get call status by call ID
                // We need to get the call ID from cache first
                $callInfo = Cache::get("threecx_call_{$participantId}");
                $callId = $callInfo['call_id'] ?? null;
                
                if ($callId) {
                    Log::info('[3CX] Participant endpoint failed, trying call endpoint', [
                        'participant_id' => $participantId,
                        'call_id' => $callId,
                        'participant_error' => $response->status()
                    ]);
                    
                    // Try to get call info by call ID (alternative approach)
                    $callUrl = rtrim($this->baseUrl, '/') . "/callcontrol/calls/{$callId}";
                    $callResponse = Http::withToken($token)
                        ->withOptions(['verify' => false])
                        ->timeout(Setting::get('integrations.threecx.timeout', 30))
                        ->accept('application/json')
                        ->get($callUrl);
                        
                    if ($callResponse->successful()) {
                        $callData = $callResponse->json();
                        
                        // Try to find our participant in the call data
                        if (isset($callData['participants']) && is_array($callData['participants'])) {
                            foreach ($callData['participants'] as $participant) {
                                if (($participant['id'] ?? null) == $participantId) {
                                    return [
                                        'success' => true,
                                        'http_status' => $callResponse->status(),
                                        'participant_id' => $participantId,
                                        'status' => $participant,
                                        'source' => 'call_endpoint'
                                    ];
                                }
                            }
                        }
                        
                        // If we can't find the specific participant, return general call status
                        return [
                            'success' => true,
                            'http_status' => $callResponse->status(),
                            'participant_id' => $participantId,
                            'status' => [
                                'status' => $callData['status'] ?? 'InProgress',
                                'callid' => $callId,
                                'id' => $participantId
                            ],
                            'source' => 'call_general'
                        ];
                    }
                }
                
                return [
                    'success' => false,
                    'http_status' => $response->status(),
                    'error' => 'Failed to get call status',
                    'message' => $response->body(),
                    'participant_id' => $participantId
                ];
            }
            
        } catch (Exception $e) {
            return [
                'success' => false,
                'http_status' => null,
                'error' => 'Exception getting call status',
                'message' => $e->getMessage()
            ];
        }
    }

    /**
     * Test the click-to-call service
     * 
     * @param string $testNumber Test phone number
     * @return array Test result
     */
    public function testService(string $testNumber = '07776668338'): array
    {
        Log::info('[3CX ClickToCall] Testing service', [
            'test_number' => $testNumber
        ]);

        // First test OAuth token
        try {
            $token = $this->authService->getToken();
            
            if (empty($token)) {
                return [
                    'success' => false,
                    'error' => 'OAuth token test failed',
                    'message' => 'Unable to obtain valid OAuth token'
                ];
            }
            
        } catch (Exception $e) {
            return [
                'success' => false,
                'error' => 'OAuth authentication failed',
                'message' => $e->getMessage()
            ];
        }

        // Test the extension status
        try {
            $statusUrl = rtrim($this->baseUrl, '/') . "/callcontrol/{$this->clientExtension}";
            
            $response = Http::withToken($token)
                ->withOptions(['verify' => false])
                ->timeout(30)
                ->accept('application/json')
                ->get($statusUrl);

            if (!$response->successful()) {
                return [
                    'success' => false,
                    'error' => 'Extension access test failed',
                    'message' => "Cannot access {$this->clientExtension} extension: " . $response->body()
                ];
            }
            
        } catch (Exception $e) {
            return [
                'success' => false,
                'error' => 'Extension status check failed',
                'message' => $e->getMessage()
            ];
        }

        // Now test actual call (with short timeout for testing)
        $callResult = $this->makeCall($testNumber, 5);
        
        return [
            'success' => true,
            'message' => 'Click-to-call service test completed',
            'oauth_test' => 'passed',
            'extension_test' => 'passed',
            'call_test' => $callResult
        ];
    }

    /**
     * Get the client extension being used
     * 
     * @return string
     */
    public function getClientExtension(): string
    {
        return $this->clientExtension;
    }

    /**
     * Check if the service is properly configured
     * 
     * @return array Configuration status
     */
    public function getConfiguration(): array
    {
        return [
            'base_url' => $this->baseUrl,
            'client_extension' => $this->clientExtension,
            'oauth_configured' => !empty(Setting::get('integrations.threecx.client_id')),
            'base_url_configured' => !empty($this->baseUrl)
        ];
    }
}