<?php

namespace App\Core\Flows;

use App\Models\ConversationState;
use App\Models\MessageLog;

/**
 * ConversationFlowEngine
 * Orchestrates multi-stage interactive conversation flows.
 */
class ConversationFlowEngine
{
    /**
     * Map of registered flow names to their classes
     */
    private static array $flows = [
        'test_flow' => TestFlow::class,
        'driver_registration_flow' => DriverRegistrationFlow::class,
        'payment_flow' => PaymentFlow::class,
        'complaint_flow' => ComplaintFlow::class,
    ];

    /**
     * Map of keyword triggers to start a specific flow
     */
    private static array $startTriggers = [
        'test' => 'test_flow',
        'اختبار' => 'test_flow',
        'سجل' => 'driver_registration_flow',
        'تسجيل' => 'driver_registration_flow',
        'register' => 'driver_registration_flow',
        'دفع' => 'payment_flow',
        'وصل' => 'payment_flow',
        'تسديد' => 'payment_flow',
        'رصيد' => 'payment_flow',
        'شكوى' => 'complaint_flow',
        'مشكلة' => 'complaint_flow',
        'بلاغ' => 'complaint_flow',
        'تظلم' => 'complaint_flow',
        'شكوي' => 'complaint_flow',
        'complaint' => 'complaint_flow',
    ];

    /**
     * Process incoming message.
     * Returns true if handled by the flow engine, false otherwise.
     */
    public static function processMessage(array $session, array $msgData): bool
    {
        // 1. Housekeeping: remove expired sessions
        ConversationState::cleanExpired();

        $phone = $msgData['phone'];
        $companyId = $session['company_id'];
        $text = isset($msgData['body']) ? trim($msgData['body']) : '';

        // If incoming message is audio, transcribe it via Gemini (if limits permit)
        $isAudio = !empty($msgData['audio']) && !empty($msgData['mimeType']);
        if ($isAudio) {
            if ($companyId !== 1) {
                $activeSub = \App\Models\CompanySubscription::findActiveByCompany($companyId);
                if (!$activeSub) {
                    error_log("[Flow Engine Warning] Company {$companyId} has no active subscription for audio transcription.");
                    return false;
                }
                if (!\App\Models\CompanySubscriptionUsage::hasRemainingLimit($companyId, 'request')) {
                    error_log("[Flow Engine Warning] Company {$companyId} has exceeded its request limit for audio transcription.");
                    return false;
                }
                if (!\App\Models\CompanySubscriptionUsage::hasRemainingLimit($companyId, 'voice')) {
                    error_log("[Flow Engine Warning] Company {$companyId} has exceeded its voice limit for audio transcription.");
                    return false;
                }
            }

            $rule = \App\Models\ChatbotRule::findActiveForRule($companyId);
            $configuredGeminiKey = ($rule && !empty($rule['gemini_api_key'])) ? $rule['gemini_api_key'] : null;
            $apiKey = \App\Services\GeminiService::getGeminiApiKey($configuredGeminiKey);
            if (!empty($apiKey)) {
                $transcription = \App\Services\GeminiService::transcribeAudio($apiKey, $msgData['audio'], $msgData['mimeType']);
                if ($transcription) {
                    $text = $transcription;
                    $msgData['body'] = $transcription;
                    // Increment usage stats for successful transcription
                    if ($companyId !== 1) {
                        \App\Models\CompanySubscriptionUsage::incrementUsage($companyId, 'voice');
                        \App\Models\CompanySubscriptionUsage::incrementUsage($companyId, 'request');
                    }
                }
            }
        }

        // 2. Lookup existing active flow
        $state = ConversationState::findActive($companyId, $phone);

        $flowName = '';
        $currentStep = '';
        $context = [];

        if ($state) {
            $flowName = $state['flow_name'];
            $currentStep = $state['current_step'];
            $context = json_decode($state['context_data'] ?: '{}', true) ?: [];
        } else {
            // Check if message is a starting trigger for a new flow
            $normalizedText = strtolower(trim($text));
            if (isset(self::$startTriggers[$normalizedText])) {
                $flowName = self::$startTriggers[$normalizedText];
                $currentStep = 'start';
                $context = [];
            }
        }

        // If no active flow and no trigger matches, pass control back to normal bot rules
        if (empty($flowName) || !isset(self::$flows[$flowName])) {
            return false;
        }

        // Check subscription limits for active/starting flow
        if ($companyId !== 1) {
            $activeSub = \App\Models\CompanySubscription::findActiveByCompany($companyId);
            if (!$activeSub) {
                error_log("[Flow Engine Warning] Company {$companyId} has no active subscription.");
                self::sendReply($session, $phone, "⚠️ عذراً، لا يوجد اشتراك نشط لهذا المتجر حالياً.");
                return true;
            }
            if (!\App\Models\CompanySubscriptionUsage::hasRemainingLimit($companyId, 'request')) {
                error_log("[Flow Engine Warning] Company {$companyId} has exceeded its general request limit.");
                self::sendReply($session, $phone, "⚠️ عذراً، لقد استهلك هذا المتجر كامل الحد المسموح له من الرسائل والطلبات لهذا الشهر.");
                return true;
            }
        }

        // 3. User cancel flow option
        $normalizedCancel = strtolower(trim($text));
        if (in_array($normalizedCancel, ['إلغاء', 'خروج', 'cancel', 'exit'])) {
            if ($state) {
                ConversationState::deleteState($state['id']);
                $cancelMsg = in_array($normalizedCancel, ['cancel', 'exit']) 
                    ? 'Interactive flow cancelled.' 
                    : 'تم إلغاء المحادثة التفاعلية.';
                self::sendReply($session, $phone, $cancelMsg);
                return true;
            }
        }

        // 4. Instantiate and execute the flow
        $flowClass = self::$flows[$flowName];
        /** @var BaseFlow $flowInstance */
        $flowInstance = new $flowClass();

        try {
            $context['company_id'] = $companyId;
            $result = $flowInstance->handleStep($currentStep, $msgData, $context);

            if ($result->isFinished()) {
                // Flow has reached terminal state: clean up DB record
                if ($state) {
                    ConversationState::deleteState($state['id']);
                }
            } else {
                // Flow has next step: save or update state record (TTL: 1 hour)
                ConversationState::saveState([
                    'company_id' => $companyId,
                    'contact_phone' => $phone,
                    'flow_name' => $flowName,
                    'current_step' => $result->getNextStep(),
                    'context_data' => json_encode($context, JSON_UNESCAPED_UNICODE),
                    'expires_at' => date('Y-m-d H:i:s', strtotime('+1 hour'))
                ]);
            }

            // 5. Send reply if one is provided
            $replySent = false;
            if ($companyId === 1 && $flowName === 'driver_registration_flow' && $result->getReplyText() !== '') {
                $rule = \App\Models\ChatbotRule::findActiveForRule($companyId);
                $configuredGeminiKey = ($rule && !empty($rule['gemini_api_key'])) ? $rule['gemini_api_key'] : null;
                $apiKey = \App\Services\GeminiService::getGeminiApiKey($configuredGeminiKey);
                
                if (!empty($apiKey)) {
                    $configuredElKey = ($rule && !empty($rule['elevenlabs_api_key'])) ? $rule['elevenlabs_api_key'] : null;
                    $elApiKey = \App\Services\GeminiService::getElevenLabsApiKey($configuredElKey);
                    
                    $configuredVoiceId = ($rule && !empty($rule['elevenlabs_voice_id'])) ? $rule['elevenlabs_voice_id'] : null;
                    $elVoiceId = \App\Services\GeminiService::getElevenLabsVoiceId($configuredVoiceId);

                    // Generate the audio voice note
                    $audioData = \App\Services\GeminiService::generateAudioResponse(
                        $apiKey,
                        "أنت سارة، مساعدة فريق خدمة العملاء في تطبيق سيرو (Siro) — أول منصة نقل ذكية وبنية تحتية رقمية للتنقل في سوريا والأردن ومصر. تتحدثين بلهجة سورية دافئة ومحببة ومهنية جداً كأنك إنسان حقيقي.

معلومات عن سيرو:
- التطبيق: سيرو (Siro) — من تطوير سيرو لنقل الركاب
- العمولة: 11% فقط (أقل عمولة في السوق السوري)
- التحميل: أندروید https://play.google.com/store/apps/details?id=com.Siro.siro | آيفون https://apps.apple.com/app/id6748075179
- طرق الشحن: سيريتيل كاش، شام كاش، المحفظة الداخلية
- أنواع الرحلات: 10 أنواع (مريح، سريع، سائقات، سكوتر، فان، VIP، اقتصاد، سعر ثابت، رايح جاي، كهربائي)
- المميزات: خرائط مملوكة SiroMaps، ترخيص حكومي NANS، 4 تطبيقات متكاملة، توثيق بالذكاء الاصطناعي، زر SOS، رحلات للسائقات
- الأمان: JWT + بصمة جهاز، تشفير AES-256-GCM، حماية من الاحتيال
- البلدان: سوريا (شغال)، مصر (جاهز)، الأردن (قريباً)
- الدعم: support@intaleqapp.com | support@siromove.com

ملاحظة: إذا المستخدم كتب بالإنجليزية، ردي بالإنجليزية. إذا كتب بالعربية، ردي بالعربية (اللهجة السورية).",
                        $result->getReplyText(),
                        $result->getReplyText(),
                        'Puck',
                        $elApiKey,
                        $elVoiceId
                    );

                    if ($audioData && !empty($audioData['audio'])) {
                        // Send the text message first
                        self::sendReply($session, $phone, $result->getReplyText(), $result->getMediaUrl());
                        // Then send the voice note
                        self::sendReply($session, $phone, '', null, $audioData['audio'], $audioData['mimeType']);
                        $replySent = true;
                    }
                }
            }

            if (!$replySent && ($result->getReplyText() !== '' || $result->getMediaUrl() !== null)) {
                self::sendReply($session, $phone, $result->getReplyText(), $result->getMediaUrl());
            }

            return true;
        } catch (\Exception $e) {
            error_log("[ConversationFlowEngine Exception] Flow '{$flowName}' failed: " . $e->getMessage());
            return false;
        }
    }

    /**
     * Send outbound message reply via the Baileys Gateway
     */
    public static function sendReply(
        array $session,
        string $phone,
        string $message,
        ?string $mediaUrl = null,
        ?string $audioBase64 = null,
        ?string $mimetype = null,
        ?string $imageBase64 = null
    ): bool {
        $gatewayUrl = rtrim(getenv('WHATSAPP_GATEWAY_URL') ?: 'http://localhost:3722', '/');
        if (substr($gatewayUrl, -4) === '/api') {
            $sendUrl = $gatewayUrl . '/messages/send';
        } else {
            $sendUrl = $gatewayUrl . '/api/messages/send';
        }

        $payloadData = [
            'session_key' => $session['session_key'],
            'phone' => $phone
        ];

        if ($message !== '') {
            $payloadData['message'] = $message;
        }
        if ($mediaUrl !== null) {
            $payloadData['media_url'] = $mediaUrl;
        }
        if ($audioBase64 !== null) {
            $payloadData['audio'] = $audioBase64;
        }
        if ($mimetype !== null) {
            $payloadData['mimetype'] = $mimetype;
        }
        if ($imageBase64 !== null) {
            $payloadData['image'] = $imageBase64;
        }

        $payload = json_encode($payloadData);

        $ch = curl_init($sendUrl);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
        curl_setopt($ch, CURLOPT_HTTPHEADER, [
            'Content-Type: application/json',
            'X-Webhook-Secret: ' . getenv('WEBHOOK_SECRET')
        ]);
        curl_setopt($ch, CURLOPT_TIMEOUT, 10);
        
        $response = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);

        $status = 'failed';
        $errorMsg = null;
        $waMsgId = null;

        if ($httpCode === 200) {
            $status = 'sent';
            $resData = json_decode($response, true);
            $waMsgId = $resData['data']['key']['id'] ?? null;
        } else {
            $resData = json_decode($response, true);
            $errorMsg = $resData['error'] ?? 'HTTP Code ' . $httpCode;
            error_log("[Flow Engine Gateway Error] Failed to send: " . $errorMsg);
        }

        $msgType = ($audioBase64 !== null || $mediaUrl !== null) ? 'audio' : 'text';

        // Log the outbound auto-reply message
        MessageLog::logMessage([
            'company_id' => $session['company_id'],
            'session_id' => $session['id'],
            'contact_phone' => $phone,
            'direction' => 'outbound',
            'message_type' => $msgType,
            'message_body' => $message,
            'media_url' => $mediaUrl,
            'whatsapp_message_id' => $waMsgId,
            'status' => $status,
            'error_message' => $errorMsg
        ]);
        
        return $status === 'sent';
    }
}
