<?php


namespace App\Traits;


use App\DataTables\UserCampaignEmailDatatable;
use App\Email_templates;
use App\Tools\SendinBlueEmailService;
use App\UserEmailCampaign;
use App\UserMailingList;
use Carbon\Carbon;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\URL;

/**
 * Handles client campaign emails to Mailchimps
 * Trait ClientCampaignEmail
 * @package App\Traits
 */
trait ClientCampaignEmail
{

    // ============================== SENDINBLUE ============================== //

    private $senderEmail;
    private $sendinblue;

    public function __construct(){
        $this->senderEmail = 'support@npontu.com';
        $this->sendinblue = new SendinBlueEmailService();
    }


    public function getUserMailList(){
        // Get current user mail folder data
        $currentUser = \auth()->user();
        $userMailLists = $currentUser->mailing_list()->pluck('api_mail_list_id')->toArray();

        $sendinblue = new SendinBlueEmailService();

        //=================== Get data from API ===================//
        $preMailListContent = $sendinblue->getApiCall('get-lists')['lists'] ?? [];
        $mailContentCollection = collect($preMailListContent);

        return $mailContentCollection->whereIn('id',$userMailLists);
    }


    public function getUserMailListData(UserMailingList $userMailList){

        try {
            return response()->json([
                'code' => 200,
                'status' => 'success',
                'data' => $userMailList,
                'message' => 'Getting data was successful'
            ]);

        } catch (\Exception $exception){

            return response()->json([
                'code' => 401,
                'status' => 'failed',
                'data' => $exception->getMessage(),
                'message' => 'Getting data failed'
            ]);
        }
    }


    public function campaignsList(UserCampaignEmailDatatable $table)
    {
        return $table->render('sendinblue.campaigns.index');
    }


    public function campaignCreate(Request $request)
    {
        $user = Auth::user();
        $mails_sent = $user->emailSentCount();
        if (request()->isMethod('POST')) {
           return $this->campaignStore($request);
        }

        //get all mailing list
        $listFromApi = $this->getUserMailList()->pluck('id')->toArray();
        $mailingLists = $user->mailing_list()->whereIn('api_mail_list_id', $listFromApi)->get();

        $limit = $user->subscriptionLimits();// check for subscription limits and redirect accordingly

        if(isset($limit) && $limit->no_emails <= $mails_sent):
            $route = $user->under_reseller() ? url()->previous():  route('email.subscription.index');
            return redirect($route)->withErrors(
                "You have reached your mail sending limit of $limit->no_emails  !!"
            );
        endif;


        if(!isset($limit)):
            $route = $user->under_reseller() ? url()->previous():  route('email.subscription.index');
            $flash = $user->under_reseller() ? 'Contact your account administrator to sign up on a mail package': 'kindly choose a package here !!';
            return redirect($route)->withErrors($flash);
        endif;


        return view('sendinblue.campaigns.create')->with(['mailingLists' => $mailingLists]);
    }


    private function campaignStore(Request $request)
    {

        $user = Auth::user();
        $request->validate(
            [
                'user_mailing_list_id' => 'required|integer',
                'tag' => 'nullable|string',
                'campaign_name' => 'required|string',
                'subject' => 'required|string',
                'from_name' => 'required|string',
                'reply_to' => 'required|email',
                'company_email' => 'required',
                'email_footer' => 'nullable',
                'schedule_at' => 'required|date_format:Y-m-d\TH:i|after:' . date('Y-m-d\TH:i', strtotime('+5 minute')),
                'message' => 'required|min:5',
                'attachment_file' => 'nullable|mimes:jpeg,png,gif,pdf,doc,docx,xls,xlsx|max:10240',
            ]
        );


        //get the submitted data
        $data = request()->all();
        $data['email_pricing_id'] = $user->subscription->email_pricing_id;
        $data['status'] = 'pending';

        $flash = "Campaign mail has been successfully Created & scheduled.";

        //get the mailing list
        UserMailingList::query()->find(request()->get('user_mailing_list_id'));

        DB::beginTransaction();

        try {
            // Get the list_id and save list locally
            // Continue Campaign process by pushing it to SendinBlue API from Cronjob
            $userMailCampaign = auth()->user()->user_email_campaigns()->create($data);

            if ($request->hasFile('attachment_file')) {
                $this->saveAttachmentFile($request->file('attachment_file'), $userMailCampaign);
            }

            $this->appLog('Successfully created campaign| Campaign: ' . json_encode($userMailCampaign));
            DB::commit();
        }
        catch (\Exception $exception){
            DB::rollBack();
            $this->appLog('An Error Occurred while creating campaign! | Error: ' . json_encode($exception->getMessage()));
            return back()->with('error', 'An Error Occurred while creating campaign! ' . $exception->getMessage());
        }


        session()->flash('success', $flash);

        return redirect()->route('email.campaigns.index');
    }


    public function campaignSend($campaignId)
    {
        $sendinblue = new SendinBlueEmailService();

        //find the campaign mail
        $campaignMail = UserEmailCampaign::query()->find($campaignId);
        $endpoint = 'send-campaign-email';

        $formData = [
            'campaignId' => $campaignId->mail_campaign_id ?? ''
        ];

        $response =  $sendinblue->postApiCall($endpoint, $formData);

        if (isset($response['sent_status']) && $response['sent_status'] == true){
            $this->appLog("Successful in sending campaign now " . json_encode($response));
            $campaignMail->update(['count'=>++$campaignMail->count,'is_sent'=>true]);

        }
        else{
            $this->appLog("Error encountered while sending campaign now " . json_encode($response));

            $message = $response['message'] ?? '';
            if (empty($campaignId->mail_campaign_id)){
                $message = "You can only resend mail when the campaign has gone through";
            }

            session()->flash('error', "Campaign mail could not be Sent!! " .$message);
            return back();
        }

        session()->flash('success', "Campaign mail sent successfully.");
        return redirect()->route('email.campaigns.index');
    }


    public function campaignEdit(Request $request,UserEmailCampaign  $emailCampaign)
    {
        $user = Auth::user();

        //get all mailing list
        $listFromApi = $this->getUserMailList()->pluck('id')->toArray();
        $mailingLists = $user->mailing_list()->whereIn('api_mail_list_id', $listFromApi)->get();

        $limit = $user->subscriptionLimits();// check for subscription limits and redirect accordingly

        if(!isset($limit)):
            $route = $user->under_reseller() ? url()->previous():  route('email.subscription.index');
            $flash = $user->under_reseller() ? 'Contact your account administrator to sign up on a mail package': 'kindly choose a package here !!';
            return redirect($route)->withErrors($flash);
        endif;


        return  $request->isMethod('post') ?
            $this->campaigUpdate($request,$emailCampaign) :
            view('sendinblue.campaigns.edit', ['mailingLists' => $mailingLists,'emailCampaign'=>$emailCampaign]);
    }


    private function campaigUpdate($request,$emailCampaign)
    {
        request()->validate(
            [
                'user_mailing_list_id' => 'required|integer',
                'tag' => 'nullable|string',
                'campaign_name' => 'required|string',
                'subject' => 'required|string',
                'from_name' => 'required|string',
                'reply_to' => 'required|email',
                'company_email' => 'required',
                'email_footer' => 'nullable',
                'schedule_at' => 'required|date_format:Y-m-d\TH:i|after:' . date('Y-m-d\TH:i', strtotime('+5 minute')),
                'message' => 'required|min:5',
                'attachment_file' => 'nullable|mimes:jpg,jpeg,png,gif,pdf,doc,docx,xls,xlsx|max:10240',
            ]
        );

        // Get the submitted data
        $data = request()->all();
        $data['status'] = 'update';
        $data['is_sent'] = false;

        DB::beginTransaction();

        try {
            // Update & continue Campaign process ...
            // by pushing it to SendinBlue API from Cronjob
            $emailCampaign->update($data);

            if ($request->hasFile('attachment_file')) {
                $this->saveAttachmentFile($request->file('attachment_file'), $emailCampaign);
            }
            $this->appLog('Successfully updated campaign| Campaign: ' . json_encode($emailCampaign));
            DB::commit();
        }
        catch (\Exception $exception){
            DB::rollBack();
            $this->appLog('An Error Occurred while updating campaign! | Error: ' . json_encode($exception->getMessage()));
            return back()->with('error', 'An Error Occurred while updating campaign! ' . $exception->getMessage());
        }

        session()->flash('success', "Campaign mail Updated & Scheduled successfully");

        return redirect()->route('email.campaigns.index');
    }


    public function campaignDelete($id)
    {
        //find the campaign mail
        $campaignMail = UserEmailCampaign::query()->find($id);

        $sendinblueCampaignId = $campaignMail->mail_campaign_id;

        if (empty($sendinblueCampaignId)){
            $campaignMail->delete();
            $this->sendinblue->appLog("Campaign mail deleted successfully.");
        }
        else {
            $endpoint = "delete-campaign-email/{$sendinblueCampaignId}";

            // Push to sendinblue
            $response = $this->sendinblue->deleteApiCall($endpoint);

            // If deletion successful, delete campaign locally
            if (isset($response['status_of_delete'])) {
                $campaignMail->delete();
                $this->sendinblue->appLog("Campaign mail deleted successfully.");
            } else {
                $message = $response['message'] ?? '';
                $this->sendinblue->appLog("Error Encountered while Deleting campaign mail");
                session()->flash('error', "Campaign mail could not be deleted!! " . $message);
                return back();
            }

        }

        session()->flash('success', "Campaign mail deleted successfully.");
        return back();
    }

    public function saveAttachmentFile($attachmentFile, $userMailCampaign): array
    {
        // Generate a unique filename for the uploaded file and get file extension
        $file_extension = $attachmentFile->getClientOriginalExtension();
        $filename = uniqid() . '.' . $file_extension;

        // Save the file to the storage path
        $path = $attachmentFile->storeAs('public/UserCampaignAttachment', $filename);

        // Generate url to imported file by concatenating the domain with the path to the file
        $file_url = $this->getCurrentDomain() . Storage::url($path);


        // Save data for user email campaign attachment contact file import details
        $attachment = $userMailCampaign->user_email_campaign_attachment()->create([
            'file_name' => $filename,
            'file_extension' => $file_extension,
            'file_path' => $path,
            'file_url' => $file_url
        ]);

        return [
            'fileAttachment' => $attachment,
        ];
    }

    public function getCurrentDomain(): string
    {
        $domainEnv = env('APP_URL');

        $url = URL::current();
        $parsedUrl = parse_url($url);
        $domain = $parsedUrl['host'] ?? '';

        return $domainEnv ?? $domain;
    }


    public function appLog($message)
    {
        Log::channel('api_request')->info("\n");
        Log::channel('api_request')->info($message);
    }

    // ============================== SENDINBLUE ============================== //


    public function campaignCreateOld(Request $request)
    {
        $user = Auth::user();
        $mails_sent = $user->emailSentCount();
        if (request()->isMethod('POST')) {
            return $this->campaignStore($request);
        }

        //get all mailing list
        $mailingLists = $user->mailing_list()->where('status','published')->get();
        $templates = $user->user_templates;

        $limit = $user->subscriptionLimits();// check for subscription limits and redirect accordingly

        if(isset($limit) && $limit->no_emails <= $mails_sent):
            $route = $user->under_reseller() ? url()->previous():  route('email.subscription.index');
            return redirect($route)->withErrors(
                "You have reached your mail sending limit of $limit->no_emails  !!"
            );
        endif;


        if(!isset($limit)):
            $route = $user->under_reseller() ? url()->previous():  route('email.subscription.index');
            $flash = $user->under_reseller() ? 'Contact your account administrator to sign up on a mail package': 'kindly choose a package here !!';
            return redirect($route)->withErrors($flash);
        endif;



        return view('chimp.group.create')->with(['mailingLists' => $mailingLists,'templates' => $templates]);
    }

    public function campaignEditOld(Request $request,UserEmailCampaign  $emailCampaign)
    {
        $user = Auth::user();
        $templates = $user->user_templates;
        $mailingLists = $user->mailing_list()->where('status','published')->get();

        $limit = $user->subscriptionLimits();// check for subscription limits and redirect accordingly


        if(!isset($limit)):
            $route = $user->under_reseller() ? url()->previous():  route('email.subscription.index');
            $flash = $user->under_reseller() ? 'Contact your account administrator to sign up on a mail package': 'kindly choose a package here !!';
            return redirect($route)->withErrors($flash);
        endif;


        return  $request->isMethod('post') ? $this->campaigUpdate($request,$emailCampaign) : view('chimp.group.edit',
            ['mailingLists' => $mailingLists,'templates' => $templates,'emailCampaign'=>$emailCampaign]
        );
    }

    private function campaignStoreOld(Request $request)
    {

        $user = Auth::user();
        $request->validate(
            [
                'user_mailing_list_id' => 'required|integer',
                'subject' => 'required|string',
                'mail_template_id' => 'required|string',
                'from_name' => 'required|string',
                'reply_to' => 'required|email',
            ]
        );

        //get the submitted data
        $data = request()->all();
        $data['email_pricing_id'] = $user->subscription->email_pricing_id;
        $template = Email_templates::query()->find($data['mail_template_id']);


        if($template->type == 'header/footer')
            request()->validate(['message' => 'required']);

        $flash ="Campaign mail saved successfully. You can now send the campaign to the recipients by clicking on the blue button (send button)";
        DB::beginTransaction();

        //get the mailing list
        $mailingList = UserMailingList::query()->find(request()->get('user_mailing_list_id'));

        //get the list_id
        $listId = $mailingList->list_id;
        $userCampaign = auth()->user()->user_email_campaigns()->create($data);

        if($userCampaign->mail_template->type == 'image')  //set the message body to null because of the template type
            $userCampaign->update(['message'=>null]);


        //save and send campaign email
        try {
            //store campaign mail
            $response = $this->storeCampaignMailToMailchimp($listId, $userCampaign);


            //if response is not an error, update the campaign with content
            if (!$this->isErrorFromMailchimp($response['status']))
            {

                //update the user campaign both locally and on mailchimp with the campaign id
                $userCampaign->update(['mail_campaign_id' => $response['id']]);

                //update the campaign on mailchimp
                $this->updateCampaignOnMailchimp($response['id'], $userCampaign);

                if($request->has('submit')){
                    $this->campaignSend($userCampaign->id);
                    $flash = 'Campaign successfully sent and saved';
                }


                DB::commit();

                session()->flash('success', $flash);

                return redirect()->route('email.campaigns.index');
            }

            return  $this->rollBackAndSendBackWithError($this->parseMailchimpError($response));

        } catch (\Exception $e) {
            return $this->rollBackAndSendBackWithError($e->getMessage());
        }
    }

    private function campaigUpdateOld($request,$emailCampaign)
    {
        request()->validate(
            [
                'user_mailing_list_id' => 'required|integer',
                'subject' => 'required|string',
                'mail_template_id' => 'required|string',
                'from_name' => 'required|string',
                'message' => 'required|string',
                'reply_to' => 'required|email',
            ]
        );




        //get the submitted data
        $data = request()->all();

        DB::beginTransaction();

        //get the mailing list
        $mailingList = UserMailingList::query()->find(request()->get('user_mailing_list_id'));

        //get the list_id
        $listId = $emailCampaign->user_mailing_list->list_id;



        //save and send campaign email
        try {
            //store campaign mail


            //if response is not an error, update the campaign with content

               $emailCampaign->update($data);
               $response = $this->updateCampaignOnMailchimp($emailCampaign->mail_campaign_id, $emailCampaign);


            if (isset($response['id'])) {
                //update the user campaign both locally and on mail chimp with the campaign id
                $emailCampaign->update($data);

                //update the campaign on mail chimp

                DB::commit();
                session()->flash('success', "Campaign mail saved successfully. You can now send the campaign to the recipients");
                return redirect()->route('email.campaigns.index');
            }

            return redirect()->back()->withErrors('Sorry campaign could not be saved kindly contact support for assistance !!');

        } catch (\Exception $e) {

            return $this->rollBackAndSendBackWithError($e->getMessage());
        }
    }

    private function parseMailchimpError($response)
    {
        $errorMessage = ' Error: ';
        //get the errors
        $errors = $response['errors'];
        foreach ($errors as $error) {
            $errorMessage .= $error['message'] . '.';
        }

        return $errorMessage;
    }

    private function rollBackAndSendBackWithError($message)
    {
        DB::rollBack();
        session()->flash('error', $message);
        return back()->withInput();
    }

    private function storeCampaignMailToMailchimp($listId, UserEmailCampaign $userEmailCampaign)
    {

        $template_id = $userEmailCampaign->mail_template->type == 'image' ? $this->bodyImage_template : $this->headerFooter_template;

        $chimp = $this->init();

        //save the campaign
        return $chimp->post('campaigns', [
            'type' => 'regular',
            'recipients' => [
                'list_id' => $listId,
            ],
            'settings' => [
                'from_name' =>    $userEmailCampaign->from_name,
                'reply_to' =>     $userEmailCampaign->reply_to,
                'subject_line' => $userEmailCampaign->subject,
                'preview_text' => $userEmailCampaign->subject,
                'title' =>        $userEmailCampaign->subject,
                'template_id' =>  $template_id,
            ],
        ]);

    }

    private function updateCampaignOnMailchimp($campaignId, $userData)
    {

        $chimp = $this->init();
        $app = env('APP_URL');
        $path =  "$app/storage/template/";
        $template_id = $userData->mail_template->type == 'image' ? $this->bodyImage_template : $this->headerFooter_template;

        $body_imageContent = [
                'body'     => '<img  class="deviceWidth" src="'.$path.$userData->mail_template->body_image.'"   alt="" border="0" width="100%">',
                'subject'  => $userData->subject,
        ];

        $headerFooterContent = [
            'body'     => $userData->message,
            'subject'  => $userData->subject,
            'header'   => '<img  class="deviceWidth" src="'.$path.$userData->mail_template->template_head_image.'"   alt="" border="0" width="100%">',
            'footer'   => '<img  class="deviceWidth" src="'.$path.$userData->mail_template->template_footer_image.'" alt="" border="0" width="100%">',
        ];


        //update campaign
        return $chimp->put("campaigns/{$campaignId}/content", [
            'template' => [
                'id' => $template_id,
                'sections' => $userData->mail_template->type == 'image' ?  $body_imageContent  : $headerFooterContent,
                ]
        ]);
    }

    public function campaignSendOld($id)
    {
        //find the campaign mail
        $campaignMail = UserEmailCampaign::query()->find($id);

        $chimp = $this->init();
//        //send campaign
//        $isSent = $campaignMail->is_sent ?
//            $chimp->post("campaigns/{$campaignMail->mail_campaign_id}/actions/test",[
//            'test_emails'=> [
//                 'oboateng@npontu.com','listermatrix360@gmail.com'
//                ],
//            'send_type'=>'html'
//        ])
//            :
           $isSent = $chimp->post("campaigns/{$campaignMail->mail_campaign_id}/actions/send");


        if (!$isSent)
            return  $this->rollBackAndSendBackWithError("Sorry, an error occurred in sending campaign mail");

        $campaignMail->update(['count'=>++$campaignMail->count,'is_sent'=>true]);



        session()->flash('success', "Campaign mail sent successfully.");
        return redirect()->route('email.campaigns.index');
    }

    public function campaignDeleteOld($id)
    {
        //find the campaign mail
        $campaignMail = UserEmailCampaign::query()->find($id);

        $chimp = $this->init();
        //delete campaign
        $response = $chimp->delete("campaigns/{$campaignMail->mail_campaign_id}");

        //if response is not  an error, delete on local db as well
        if (is_bool($response)) {
            $campaignMail->delete();
            session()->flash('success', "Campaign mail deleted successfully.");
            return back();
        }

        session()->flash('error', "Campaign mail could not be deleted.");
        return back();
    }

    private function isErrorFromMailchimp($status) {
        $errorCodes = [];

        for ($errorCode = 400; $errorCode <= 505; $errorCode++) {
            array_push($errorCodes, $errorCode);
        }

       return collect($errorCodes)->contains($status);
    }

}
