<?php
/**
 * Service Twilio Voice
 * Gestion des appels vocaux entrants et sortants
 */

namespace App\Services;

class TwilioVoiceService
{
    private string $accountSid;
    private string $authToken;
    private string $phoneNumber;
    private string $webhookBaseUrl;
    
    public function __construct()
    {
        $this->accountSid = TWILIO_ACCOUNT_SID;
        $this->authToken = TWILIO_AUTH_TOKEN;
        $this->phoneNumber = TWILIO_PHONE_NUMBER;
        $this->webhookBaseUrl = TWILIO_WEBHOOK_BASE_URL;
    }
    
    /**
     * Générer TwiML pour le message de bienvenue
     */
    public function generateWelcomeResponse(array $entreprise, string $langue = 'fr'): string
    {
        $messages = $this->getVoiceMessages($langue);
        $welcomeMessage = $entreprise['voice_welcome'] ?? $messages['welcome'];
        
        $twiml = '<?xml version="1.0" encoding="UTF-8"?>';
        $twiml .= '<Response>';
        $twiml .= $this->say($welcomeMessage, $langue);
        $twiml .= '<Gather input="speech dtmf" timeout="' . TWILIO_INPUT_TIMEOUT . '" ';
        $twiml .= 'action="' . $this->webhookBaseUrl . '/api/twilio/gather" method="POST" ';
        $twiml .= 'language="' . $this->getTwilioLanguage($langue) . '">';
        $twiml .= $this->say($messages['menu'], $langue);
        $twiml .= '</Gather>';
        $twiml .= $this->say($messages['no_input'], $langue);
        $twiml .= '<Redirect>' . $this->webhookBaseUrl . '/api/twilio/voice</Redirect>';
        $twiml .= '</Response>';
        
        return $twiml;
    }
    
    /**
     * Générer TwiML pour enregistrer un message vocal
     */
    public function generateRecordResponse(string $langue = 'fr'): string
    {
        $messages = $this->getVoiceMessages($langue);
        
        $twiml = '<?xml version="1.0" encoding="UTF-8"?>';
        $twiml .= '<Response>';
        $twiml .= $this->say($messages['record_prompt'], $langue);
        $twiml .= '<Record maxLength="' . TWILIO_MAX_RECORDING_DURATION . '" ';
        $twiml .= 'action="' . $this->webhookBaseUrl . '/api/twilio/recording" ';
        $twiml .= 'transcribe="' . (TWILIO_ENABLE_TRANSCRIPTION ? 'true' : 'false') . '" ';
        $twiml .= 'transcribeCallback="' . $this->webhookBaseUrl . '/api/twilio/transcription" ';
        $twiml .= 'playBeep="true" />';
        $twiml .= $this->say($messages['record_timeout'], $langue);
        $twiml .= '</Response>';
        
        return $twiml;
    }
    
    /**
     * Générer TwiML pour transférer à un agent
     */
    public function generateTransferResponse(string $agentPhone, string $langue = 'fr'): string
    {
        $messages = $this->getVoiceMessages($langue);
        
        $twiml = '<?xml version="1.0" encoding="UTF-8"?>';
        $twiml .= '<Response>';
        $twiml .= $this->say($messages['transfer'], $langue);
        $twiml .= '<Dial callerId="' . $this->phoneNumber . '" timeout="30" ';
        $twiml .= 'action="' . $this->webhookBaseUrl . '/api/twilio/dial-status">';
        $twiml .= '<Number>' . $agentPhone . '</Number>';
        $twiml .= '</Dial>';
        $twiml .= $this->say($messages['agent_unavailable'], $langue);
        $twiml .= '<Redirect>' . $this->webhookBaseUrl . '/api/twilio/voicemail</Redirect>';
        $twiml .= '</Response>';
        
        return $twiml;
    }
    
    /**
     * Générer TwiML pour la messagerie vocale
     */
    public function generateVoicemailResponse(string $langue = 'fr'): string
    {
        $messages = $this->getVoiceMessages($langue);
        
        $twiml = '<?xml version="1.0" encoding="UTF-8"?>';
        $twiml .= '<Response>';
        $twiml .= $this->say($messages['voicemail'], $langue);
        $twiml .= '<Record maxLength="' . TWILIO_MAX_RECORDING_DURATION . '" ';
        $twiml .= 'action="' . $this->webhookBaseUrl . '/api/twilio/voicemail-saved" ';
        $twiml .= 'transcribe="true" ';
        $twiml .= 'transcribeCallback="' . $this->webhookBaseUrl . '/api/twilio/transcription" ';
        $twiml .= 'playBeep="true" />';
        $twiml .= '</Response>';
        
        return $twiml;
    }
    
    /**
     * Générer TwiML de fin d'appel
     */
    public function generateGoodbyeResponse(string $langue = 'fr'): string
    {
        $messages = $this->getVoiceMessages($langue);
        
        $twiml = '<?xml version="1.0" encoding="UTF-8"?>';
        $twiml .= '<Response>';
        $twiml .= $this->say($messages['goodbye'], $langue);
        $twiml .= '<Hangup />';
        $twiml .= '</Response>';
        
        return $twiml;
    }
    
    /**
     * Générer TwiML Say avec la bonne voix/langue
     */
    private function say(string $message, string $langue = 'fr'): string
    {
        $voice = TWILIO_DEFAULT_VOICE;
        $lang = $this->getTwilioLanguage($langue);
        
        return '<Say voice="' . $voice . '" language="' . $lang . '">' . htmlspecialchars($message) . '</Say>';
    }
    
    /**
     * Convertir le code langue en format Twilio
     */
    private function getTwilioLanguage(string $langue): string
    {
        $map = [
            'fr' => 'fr-FR',
            'en' => 'en-US',
            'bm' => 'fr-FR', // Bambara -> fallback français
            'ff' => 'fr-FR', // Fulfuldé -> fallback français
            'snk' => 'fr-FR' // Soninké -> fallback français
        ];
        
        return $map[$langue] ?? 'fr-FR';
    }
    
    /**
     * Messages vocaux par langue
     */
    private function getVoiceMessages(string $langue): array
    {
        $messages = [
            'fr' => [
                'welcome' => "Bienvenue sur notre service client.",
                'menu' => "Appuyez sur 1 ou dites 'agent' pour parler à un conseiller. Appuyez sur 2 ou dites 'message' pour laisser un message vocal. Appuyez sur 3 pour nos horaires d'ouverture.",
                'no_input' => "Nous n'avons pas reçu de réponse.",
                'record_prompt' => "Après le bip, veuillez décrire votre demande. Appuyez sur dièse quand vous avez terminé.",
                'record_timeout' => "Nous n'avons pas reçu d'enregistrement.",
                'transfer' => "Veuillez patienter, nous vous mettons en relation avec un conseiller.",
                'agent_unavailable' => "Tous nos conseillers sont actuellement occupés.",
                'voicemail' => "Laissez votre message après le bip. Nous vous rappellerons dans les plus brefs délais.",
                'goodbye' => "Merci de votre appel. À bientôt.",
                'message_saved' => "Votre message a bien été enregistré. Nous vous recontacterons rapidement.",
                'hours' => "Nos horaires d'ouverture sont du lundi au vendredi de 8h à 18h."
            ],
            'en' => [
                'welcome' => "Welcome to our customer service.",
                'menu' => "Press 1 or say 'agent' to speak with an advisor. Press 2 or say 'message' to leave a voicemail. Press 3 for our opening hours.",
                'no_input' => "We did not receive any input.",
                'record_prompt' => "After the beep, please describe your request. Press pound when finished.",
                'record_timeout' => "We did not receive any recording.",
                'transfer' => "Please wait, we are connecting you with an advisor.",
                'agent_unavailable' => "All our advisors are currently busy.",
                'voicemail' => "Leave your message after the beep. We will call you back as soon as possible.",
                'goodbye' => "Thank you for your call. Goodbye.",
                'message_saved' => "Your message has been recorded. We will contact you shortly.",
                'hours' => "Our opening hours are Monday to Friday from 8am to 6pm."
            ]
        ];
        
        return $messages[$langue] ?? $messages['fr'];
    }
    
    /**
     * Passer un appel sortant
     */
    public function makeCall(string $to, string $twimlUrl): ?array
    {
        $url = "https://api.twilio.com/2010-04-01/Accounts/{$this->accountSid}/Calls.json";
        
        $data = [
            'To' => $to,
            'From' => $this->phoneNumber,
            'Url' => $twimlUrl
        ];
        
        $ch = curl_init($url);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
        curl_setopt($ch, CURLOPT_USERPWD, "{$this->accountSid}:{$this->authToken}");
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        
        $response = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);
        
        if ($httpCode >= 200 && $httpCode < 300) {
            return json_decode($response, true);
        }
        
        error_log("Twilio makeCall error: " . $response);
        return null;
    }
    
    /**
     * Valider la signature Twilio (sécurité webhook)
     */
    public function validateRequest(string $signature, string $url, array $params): bool
    {
        ksort($params);
        $data = $url;
        foreach ($params as $key => $value) {
            $data .= $key . $value;
        }
        
        $expectedSignature = base64_encode(hash_hmac('sha1', $data, $this->authToken, true));
        
        return hash_equals($expectedSignature, $signature);
    }
    
    /**
     * Obtenir les détails d'un appel
     */
    public function getCall(string $callSid): ?array
    {
        $url = "https://api.twilio.com/2010-04-01/Accounts/{$this->accountSid}/Calls/{$callSid}.json";
        
        $ch = curl_init($url);
        curl_setopt($ch, CURLOPT_USERPWD, "{$this->accountSid}:{$this->authToken}");
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        
        $response = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);
        
        if ($httpCode === 200) {
            return json_decode($response, true);
        }
        
        return null;
    }
    
    /**
     * Obtenir l'URL d'un enregistrement
     */
    public function getRecordingUrl(string $recordingSid): string
    {
        return "https://api.twilio.com/2010-04-01/Accounts/{$this->accountSid}/Recordings/{$recordingSid}.mp3";
    }
}
