<?php


    namespace App\Repositories\Eloquent;

    use App\Library\SMSCounter;
    use App\Library\Tool;
    use App\Models\Automation;
    use App\Models\ContactGroups;
    use App\Models\Contacts;
    use App\Models\Country;
    use App\Models\PhoneNumbers;
    use App\Models\PlansCoverageCountries;
    use App\Models\Senderid;
    use App\Models\SendingServer;
    use App\Models\SpamWord;
    use App\Repositories\Contracts\AutomationsRepository;
    use Illuminate\Http\JsonResponse;
    use Illuminate\Support\Facades\Auth;
    use Illuminate\Support\Facades\DB;
    use libphonenumber\NumberParseException;
    use libphonenumber\PhoneNumberUtil;
    use Throwable;

    class EloquentAutomationsRepository extends EloquentBaseRepository implements AutomationsRepository
    {

        public static array $serverPools = [];

        /**
         * EloquentCampaignRepository constructor.
         *
         * @param Automation $automations
         */
        public function __construct(Automation $automations)
        {
            parent::__construct($automations);
        }


        /**
         * @param Automation $automation
         * @param array      $input
         *
         * @return JsonResponse
         */
        public function automationBuilder(Automation $automation, array $input): JsonResponse
        {

            if (Auth::user()->sms_unit != '-1' && Auth::user()->sms_unit == 0) {
                return response()->json([
                    'status'  => 'error',
                    'message' => __('locale.campaigns.sending_limit_exceed'),
                ]);
            }


            $sms_type = $input['sms_type'];


            if (Auth::user()->customer->getOption('send_spam_message') == 'no') {
                $spamWords = SpamWord::all()->filter(function ($spamWord) use ($input) {
                    if (true === str_contains(strtolower($input['message']), strtolower($spamWord->word))) {
                        return true;
                    }

                    return false;
                });

                if ($spamWords->count()) {
                    return response()->json([
                        'status'  => 'error',
                        'message' => 'Your message contains spam words.',
                    ]);
                }
            }

            if ($sms_type == 'unicode') {
                $db_sms_type = 'plain';
            } else {
                $db_sms_type = $sms_type;
            }

            if ($sms_type == 'plain' || $sms_type == 'unicode') {
                $capabilities_type = 'sms';
            } else {
                $capabilities_type = $sms_type;
            }

            $sending_servers = SendingServer::where($db_sms_type, 1)->where('status', 1)->find($input['sending_server']);

            if (empty($sending_servers)) {
                return response()->json([
                    'status'  => 'error',
                    'message' => __('locale.campaigns.sending_server_not_available'),
                ]);
            }

            $contactGroup = ContactGroups::where('customer_id', Auth::user()->id)->where('status', true)->find($input['contact_groups']);

            if ( ! $contactGroup) {
                return response()->json([
                    'status'  => 'error',
                    'message' => __('locale.contacts.contact_group_not_found'),
                ]);
            }

            $checkExistingAutomation = Automation::where('contact_list_id', $contactGroup->id)->where('user_id', Auth::user()->id)->first();

            if ($checkExistingAutomation) {
                return response()->json([
                    'status'  => 'error',
                    'message' => __('locale.automations.automation_already_available_for_contact_group'),
                ]);
            }

            $total = $contactGroup->readCache('SubscribersCount');

            if (Auth::user()->sms_unit != '-1') {

                $coverage = PlansCoverageCountries::where('plan_id', $input['plan_id'])->pluck('options', 'country_id')->toArray();
                $keys     = array_keys($coverage);

                if (count($coverage) <= 0) {
                    return response()->json([
                        'status'  => 'error',
                        'message' => "Please add coverage on your plan.",
                    ]);
                }

                $subscriber = Contacts::where('group_id', $contactGroup->id)->where('customer_id', Auth::user()->id)->where('status', 'subscribe')->first();

                try {
                    $phoneUtil         = PhoneNumberUtil::getInstance();
                    $phoneNumberObject = $phoneUtil->parse('+' . $subscriber->phone);
                    $country_code      = $phoneNumberObject->getCountryCode();
                    $country_ids       = Country::where('country_code', $country_code)->where('status', 1)->pluck('id')->toArray();
                    $country_id        = array_intersect($keys, $country_ids);
                    $country_id        = array_values($country_id);

                    if (count($country_id) <= 0) {
                        return response()->json([
                            'status'  => 'error',
                            'message' => "Permission to send an SMS has not been enabled for the region indicated by the 'To' number: " . $subscriber->phone,
                        ]);
                    }

                    $country = Country::find($country_id[0]);

                    if (is_array($coverage) && array_key_exists($country->id, $coverage)) {
                        $priceOption = json_decode($coverage[$country->id], true);

                        $sms_count = 1;
                        $price     = 0;

                        if (isset($input['message'])) {
                            $sms_counter  = new SMSCounter();
                            $message_data = $sms_counter->count($input['message']);
                            $sms_count    = $message_data->messages;
                        }

                        if ($sms_type == 'plain' || $sms_type == 'unicode') {
                            $unit_price = $priceOption['plain_sms'];
                            $price      = $total * $unit_price;
                        }

                        if ($sms_type == 'voice') {
                            $unit_price = $priceOption['voice_sms'];
                            $price      = $total * $unit_price;
                        }

                        if ($sms_type == 'mms') {
                            $unit_price = $priceOption['mms_sms'];
                            $price      = $total * $unit_price;
                        }

                        if ($sms_type == 'whatsapp') {
                            $unit_price = $priceOption['whatsapp_sms'];
                            $price      = $total * $unit_price;
                        }

                        $price *= $sms_count;

                        $balance = Auth::user()->sms_unit;

                        if ($price > $balance) {

                            return response()->json([
                                'status'  => 'error',
                                'message' => __('locale.campaigns.not_enough_balance', [
                                    'current_balance' => $balance,
                                    'campaign_price'  => $price,
                                ]),
                            ]);
                        }
                    } else {
                        return response()->json([
                            'status'  => 'error',
                            'message' => "Permission to send an SMS has not been enabled for the region indicated by the 'To' number: " . $subscriber->phone,
                        ]);
                    }
                } catch (NumberParseException $exception) {
                    return response()->json([
                        'status'  => 'error',
                        'message' => $exception->getMessage(),
                    ]);
                }
            }

            if ($total == 0) {
                return response()->json([
                    'status'  => 'error',
                    'message' => __('locale.campaigns.contact_not_found'),
                ]);
            }

            $new_automation = Automation::create([
                'user_id'           => Auth::user()->id,
                'name'              => $input['name'],
                'message'           => $input['message'],
                'sms_type'          => $sms_type,
                'contact_list_id'   => $contactGroup->id,
                'timezone'          => $input['timezone'],
                'data'              => json_encode([
                    'options' => [
                        'before' => $input['before'],
                        'at'     => $input['at'],
                    ],
                ]),
                'status'            => $automation::STATUS_ACTIVE,
                'sending_server_id' => $sending_servers->id,
            ]);

            if ( ! $new_automation) {
                return response()->json([
                    'status'  => 'error',
                    'message' => __('locale.exceptions.something_went_wrong'),
                ]);
            }


            if (isset($input['dlt_template_id'])) {
                $new_automation->dlt_template_id = $input['dlt_template_id'];
            }

            $sender_id = null;
            if (Auth::user()->customer->getOption('sender_id_verification') == 'yes') {
                if (isset($input['originator'])) {
                    if ($input['originator'] == 'sender_id') {

                        if ( ! isset($input['sender_id'])) {

                            $new_automation->delete();

                            return response()->json([
                                'status'  => 'error',
                                'message' => __('locale.sender_id.sender_id_required'),
                            ]);
                        }

                        $sender_id = $input['sender_id'];

                        if (is_array($sender_id) && count($sender_id) > 0) {
                            $invalid   = [];
                            $senderids = Senderid::where('user_id', Auth::user()->id)
                                ->where('status', 'active')
                                ->select('sender_id')
                                ->cursor()
                                ->pluck('sender_id')
                                ->all();

                            foreach ($sender_id as $sender) {
                                if ( ! in_array($sender, $senderids)) {
                                    $invalid[] = $sender;
                                }
                            }

                            if (count($invalid)) {

                                $new_automation->delete();

                                return response()->json([
                                    'status'  => 'error',
                                    'message' => __('locale.sender_id.sender_id_invalid', ['sender_id' => $invalid[0]]),
                                ]);
                            }
                        } else {

                            $new_automation->delete();

                            return response()->json([
                                'status'  => 'error',
                                'message' => __('locale.sender_id.sender_id_required'),
                            ]);
                        }
                    } else {

                        if ( ! isset($input['phone_number'])) {

                            $new_automation->delete();

                            return response()->json([
                                'status'  => 'error',
                                'message' => __('locale.sender_id.phone_numbers_required'),
                            ]);
                        }

                        $sender_id = $input['phone_number'];

                        if (is_array($sender_id) && count($sender_id) > 0) {
                            $type_supported = [];
                            PhoneNumbers::where('user_id', Auth::user()->id)
                                ->where('status', 'assigned')
                                ->cursor()
                                ->reject(function ($number) use ($sender_id, &$type_supported, &$invalid, $capabilities_type) {
                                    if (in_array($number->number, $sender_id) && ! str_contains($number->capabilities, $capabilities_type)) {
                                        return $type_supported[] = $number->number;
                                    }

                                    return $sender_id;
                                })->all();

                            if (count($type_supported)) {

                                $new_automation->delete();

                                return response()->json([
                                    'status'  => 'error',
                                    'message' => __('locale.sender_id.sender_id_sms_capabilities', ['sender_id' => $type_supported[0], 'type' => $db_sms_type]),
                                ]);
                            }
                        } else {

                            $new_automation->delete();

                            return response()->json([
                                'status'  => 'error',
                                'message' => __('locale.sender_id.sender_id_required'),
                            ]);
                        }
                    }
                } else {

                    $new_automation->delete();

                    return response()->json([
                        'status'  => 'error',
                        'message' => __('locale.sender_id.sender_id_required'),
                    ]);
                }
            } else if (Auth::user()->can('view_numbers') && isset($input['originator']) && $input['originator'] == 'phone_number' && isset($input['phone_number'])) {
                $sender_id = $input['phone_number'];

                if (is_array($sender_id) && count($sender_id) > 0) {
                    $type_supported = [];
                    PhoneNumbers::where('user_id', Auth::user()->id)
                        ->where('status', 'assigned')
                        ->cursor()
                        ->reject(function ($number) use ($sender_id, &$type_supported, &$invalid, $capabilities_type) {
                            if (in_array($number->number, $sender_id) && ! str_contains($number->capabilities, $capabilities_type)) {
                                return $type_supported[] = $number->number;
                            }

                            return $sender_id;
                        })->all();

                    if (count($type_supported)) {

                        $new_automation->delete();

                        return response()->json([
                            'status'  => 'error',
                            'message' => __('locale.sender_id.sender_id_sms_capabilities', ['sender_id' => $type_supported[0], 'type' => $db_sms_type]),
                        ]);
                    }
                } else {

                    $new_automation->delete();

                    return response()->json([
                        'status'  => 'error',
                        'message' => __('locale.sender_id.sender_id_required'),
                    ]);
                }
            } else {
                if (isset($input['originator'])) {
                    if ($input['originator'] == 'sender_id') {
                        if ( ! isset($input['sender_id'])) {

                            $new_automation->delete();

                            return response()->json([
                                'status'  => 'error',
                                'message' => __('locale.sender_id.sender_id_required'),
                            ]);
                        }

                        $sender_id = $input['sender_id'];
                    } else {

                        if ( ! isset($input['phone_number'])) {

                            $new_automation->delete();

                            return response()->json([
                                'status'  => 'error',
                                'message' => __('locale.sender_id.phone_numbers_required'),
                            ]);
                        }

                        $sender_id = $input['phone_number'];
                    }

                    if ( ! is_array($sender_id) || count($sender_id) <= 0) {

                        $new_automation->delete();

                        return response()->json([
                            'status'  => 'error',
                            'message' => __('locale.sender_id.sender_id_required'),
                        ]);
                    }
                }
                if (isset($input['sender_id'])) {
                    $sender_id = $input['sender_id'];
                }
            }

            $sender_id = array_filter($sender_id);
            if (count($sender_id)) {
                $new_automation->sender_id = json_encode($sender_id);
            }


            if (Auth::user()->sms_unit != '-1') {

                $coverage = PlansCoverageCountries::where('plan_id', $input['plan_id'])->pluck('options', 'country_id')->toArray();
                $keys     = array_keys($coverage);

                if (count($coverage) <= 0) {
                    return response()->json([
                        'status'  => 'error',
                        'message' => "Please add coverage on your plan.",
                    ]);
                }

                $subscriber = Contacts::where('group_id', $contactGroup->id)->where('customer_id', Auth::user()->id)->first();

                try {
                    $phoneUtil         = PhoneNumberUtil::getInstance();
                    $phoneNumberObject = $phoneUtil->parse('+' . $subscriber->phone);
                    $country_code      = $phoneNumberObject->getCountryCode();
                    $country_ids       = Country::where('country_code', $country_code)->where('status', 1)->pluck('id')->toArray();
                    $country_id        = array_intersect($keys, $country_ids);
                    $country_id        = array_values($country_id);

                    if (count($country_id) <= 0) {
                        return response()->json([
                            'status'  => 'error',
                            'message' => "Permission to send an SMS has not been enabled for the region indicated by the 'To' number: " . $subscriber->phone,
                        ]);
                    }

                    $country = Country::find($country_id[0]);

                    if (is_array($coverage) && array_key_exists($country->id, $coverage)) {
                        $priceOption = json_decode($coverage[$country->id], true);

                        $sms_count = 1;
                        $price     = 0;

                        if (isset($input['message'])) {
                            $sms_counter  = new SMSCounter();
                            $message_data = $sms_counter->count($input['message']);
                            $sms_count    = $message_data->messages;
                        }

                        if ($sms_type == 'plain' || $sms_type == 'unicode') {
                            $unit_price = $priceOption['plain_sms'];
                            $price      = $total * $unit_price;
                        }

                        if ($sms_type == 'voice') {
                            $unit_price = $priceOption['voice_sms'];
                            $price      = $total * $unit_price;
                        }

                        if ($sms_type == 'mms') {
                            $unit_price = $priceOption['mms_sms'];
                            $price      = $total * $unit_price;
                        }

                        if ($sms_type == 'whatsapp') {
                            $unit_price = $priceOption['whatsapp_sms'];
                            $price      = $total * $unit_price;
                        }

                        $price *= $sms_count;

                        $balance = Auth::user()->sms_unit;

                        if ($price > $balance) {

                            $new_automation->delete();

                            return response()->json([
                                'status'  => 'error',
                                'message' => __('locale.campaigns.not_enough_balance', [
                                    'current_balance' => $balance,
                                    'campaign_price'  => $price,
                                ]),
                            ]);
                        }
                    } else {
                        return response()->json([
                            'status'  => 'error',
                            'message' => "Permission to send an SMS has not been enabled for the region indicated by the 'To' number: " . $subscriber->phone,
                        ]);
                    }
                } catch (NumberParseException $exception) {
                    return response()->json([
                        'status'  => 'error',
                        'message' => $exception->getMessage(),
                    ]);
                }
            }


            $new_automation->cache = json_encode([
                'ContactCount'         => $total,
                'DeliveredCount'       => 0,
                'FailedDeliveredCount' => 0,
                'NotDeliveredCount'    => 0,
                'PendingContactCount'  => $total,
            ]);


            if ($sms_type == 'voice') {
                $new_automation->language = $input['language'];
                $new_automation->gender   = $input['gender'];
            }

            if ($sms_type == 'mms') {
                $new_automation->media_url = Tool::uploadImage($input['mms_file']);
            }

            if ($sms_type == 'whatsapp') {

                if (isset($input['whatsapp_language'])) {
                    $new_automation->language = $input['whatsapp_language'];
                }

                if (isset($input['whatsapp_mms_file'])) {
                    $new_automation->media_url = Tool::uploadImage($input['whatsapp_mms_file']);
                }
            }


            //finally, store data and return response
            $camp = $new_automation->save();


            if ($camp) {

                try {

                    return response()->json([
                        'status'  => 'success',
                        'message' => __('locale.automations.automation_campaign_send_successfully'),
                    ]);
                } catch (Throwable $exception) {
                    $new_automation->delete();

                    return response()->json([
                        'status'  => 'error',
                        'message' => $exception->getMessage(),
                    ]);
                }
            }

            $new_automation->delete();

            return response()->json([
                'status'  => 'success',
                'message' => __('locale.exceptions.something_went_wrong'),
            ]);
        }


        /**
         * Enable the Automation
         *
         * @param Automation $automation
         *
         * @return JsonResponse
         */
        public function enable(Automation $automation): JsonResponse
        {
            $automation->status = Automation::STATUS_ACTIVE;
            if ( ! $automation->save()) {
                return response()->json([
                    'status'  => 'error',
                    'message' => __('locale.exceptions.something_went_wrong'),
                ]);
            }

            return response()->json([
                'status'  => 'success',
                'message' => __('locale.campaigns.campaign_was_successfully_paused'),
            ]);
        }

        /**
         * Disable the Automation
         *
         * @param Automation $automation
         *
         * @return JsonResponse
         */
        public function disable(Automation $automation): JsonResponse
        {
            $automation->status = Automation::STATUS_INACTIVE;
            if ( ! $automation->save()) {
                return response()->json([
                    'status'  => 'error',
                    'message' => __('locale.exceptions.something_went_wrong'),
                ]);
            }

            return response()->json([
                'status'  => 'success',
                'message' => __('locale.campaigns.campaign_was_successfully_paused'),
            ]);
        }

        /**
         * Delete the Automation
         *
         * @param Automation $automation
         *
         * @return JsonResponse
         */
        public function delete(Automation $automation): JsonResponse
        {
            $automation->where('uid', $automation->uid)->with(['trackingLogs', 'reports'])->delete();

            return response()->json([
                'status'  => 'success',
                'message' => __('locale.automations.automation_has_been_successfully_deleted'),
            ]);
        }

        /**
         * Batch Enable
         *
         * @param array $ids
         *
         * @return JsonResponse
         */
        public function batchEnable(array $ids): JsonResponse
        {
            DB::transaction(function () use ($ids) {
                if ($this->query()->whereIn('uid', $ids)->update(['status' => 'active'])) {
                    return response()->json([
                        'status'  => 'success',
                        'message' => __('locale.automations.selected_automation_enabled'),
                    ]);
                }

                return response()->json([
                    'status'  => 'error',
                    'message' => __('locale.exceptions.something_went_wrong'),
                ]);
            });

            return response()->json([
                'status'  => 'success',
                'message' => __('locale.automations.selected_automation_enabled'),
            ]);
        }

        /**
         * Batch Disable
         *
         * @param array $ids
         *
         * @return JsonResponse
         */
        public function batchDisable(array $ids): JsonResponse
        {

            DB::transaction(function () use ($ids) {
                if ($this->query()->whereIn('uid', $ids)->update(['status' => 'inactive'])) {
                    return response()->json([
                        'status'  => 'success',
                        'message' => __('locale.automations.selected_automation_disabled'),
                    ]);
                }

                return response()->json([
                    'status'  => 'error',
                    'message' => __('locale.exceptions.something_went_wrong'),
                ]);
            });

            return response()->json([
                'status'  => 'success',
                'message' => __('locale.automations.selected_automation_disabled'),
            ]);
        }

        public function batchDelete(array $ids)
        {

            $status = Automation::whereIn('uid', $ids)
                ->with(['trackingLogs', 'reports'])
                ->delete();

            if ($status) {
                return response()->json([
                    'status'  => 'success',
                    'message' => __('locale.automations.selected_automation_deleted'),
                ]);
            }

            return response()->json([
                'status'  => 'success',
                'message' => __('locale.exceptions.something_went_wrong'),
            ]);
        }

    }
