<?php namespace JanVince\SmallContactForm\Models;

use Str;
use Model;
use URL;
use October\Rain\Router\Helper as RouterHelper;
use Cms\Classes\Page as CmsPage;
use Cms\Classes\Theme;
use JanVince\SmallContactForm\Models\Settings;
use Log;
use Validator;
use Mail;
use Request;
use Carbon\Carbon;
use View;
use App;
use System\Models\MailTemplate;
use System\Classes\MailManager;
use Twig;
use Input;
use System\Models\File;

class Message extends Model
{
    use \October\Rain\Database\Traits\Validation;

    public $table = 'janvince_smallcontactform_messages';

    public $implement = ['@RainLab.Translate.Behaviors.TranslatableModel'];

    public $timestamps = true;

    public $rules = [];

    public $translatable = [];

    protected $guarded = [];

    protected $jsonable = ['form_data'];

    public $attachMany = [
        'uploads' => 'System\Models\File',
    ];

    /**
     * Scope new messages only
     */
    public function scopeIsNew($query)
    {
        return $query->where('new_message', '=', 1);
    }

    /**
     * Scope read messages only
     */
    public function scopeIsRead($query)
    {
        return $query->where('new_message', '=', 0);
    }


    public function storeFormData($data, $formAlias, $formDescription, $formNotes){

        if(Settings::getTranslated('privacy_disable_messages_saving')) {
            return;
        }

        $output = [];
        $name_field_value = NULL;
        $email_field_value = NULL;
        $message_field_value = NULL;

        $formFields = Settings::getTranslated('form_fields');

        $uploads = [];

        foreach($data as $key => $value) {

            // skip helpers
            if(substr($key, 0, 1) == '_'){
                continue;
            }

            // skip reCaptcha
            if($key == 'g-recaptcha-response'){
                continue;
            }

            // skip non-defined fields
            // store uploaded file -- currently only one file is supported
            $fieldDefined = null;
            $fieldUpload = null;
            foreach( $formFields as $field) {
                if( $field['name'] == $key) {
                    $fieldDefined = true;
                    
                    if($field['type'] == 'file') {
                        $fieldUpload = true;
                        
                        if(!empty(Input::file($key))) {
                            $file = new File;
                            $file->data = (Input::file($key));
                            $file->is_public = true;
                            $file->save();
                            $uploads[] = $file;
                        }
                    }
                    
                }
            }

            // skip uploads
            if($fieldUpload){
                continue;
            }

            if( !$fieldDefined ) {
                Log::warning('SMALL CONTACT FORM WARNING: Found a non-defined field in sent data! Field name: ' . e($key) . ' and value: ' . e($value['value']) );
                continue;
            }

            $output[$key] = e($value['value']);

            // if email field is assigned in autoreply, save it separatelly
            if(empty($email_field_value) and $key == Settings::getTranslated('autoreply_email_field')){
                $email_field_value = e($value['value']);
            }

            // if name field is assigned in autoreply, save it separatelly
            if(empty($name_field_value) and $key == Settings::getTranslated('autoreply_name_field')){
                $name_field_value = e($value['value']);
            }

            // if message is assigned in autoreply, save it separatelly
            if(empty($message_field_value) and $key == Settings::getTranslated('autoreply_message_field')){
                $message_field_value = e($value['value']);
            }

        }

        $this->form_data = $output;
        $this->name = $name_field_value;
        $this->email = $email_field_value;
        $this->message = $message_field_value;
        $this->remote_ip = Request::ip();
        $this->form_alias = $formAlias;
        $this->form_description = $formDescription;
        $this->url = url()->full();
        $this->form_notes = $formNotes;
        $this->save();

        // Add files
        if($uploads) {
        
            foreach($uploads as $upload) {
                $this->uploads()->add($upload);
            }
        }

        return $this;
    }

    /**
     * Build and send autoreply message
     */
    public function sendAutoreplyEmail($postData, $componentProperties, $formAlias, $formDescription, $messageObject, $formNotes){

        if(!Settings::getTranslated('allow_autoreply')) {
            return;
        }

        if (!empty($componentProperties['disable_autoreply'])) {
            return;
        }

        if(!Settings::getTranslated('autoreply_email_field')) {
            Log::error('SMALL CONTACT FORM ERROR: Contact form data have no email to send autoreply message!');
            return;
        }

        /**
        *	Extract and test email field value
        */        
        $sendTo = '';

        foreach($postData as $key => $field) {
            if($key == Settings::getTranslated('autoreply_email_field')){
                $sendTo = $field['value'];
            }
        }

        $validator = Validator::make(['email' => $sendTo], ['email' => 'required|email']);

        if($validator->fails()){
            Log::error('SMALL CONTACT FORM ERROR: Email to send autoreply is not valid!' . PHP_EOL . ' Data: '. json_encode($postData) );
            return;
        }

        if( Settings::getTranslated('allow_email_queue') ){
            $method = 'queue';
        } else {
            $method = 'send';
        }

        $output = [];
        $outputFull = [];
        $formFields = Settings::getTranslated('form_fields');

        foreach($formFields as $field) {

            if(!empty($field['type'] and $field['type'] == 'file')) {
                continue;
            }

            $fieldValue = null;

            if( !empty( $postData[ $field['name'] ]['value'] ) ) {
                $fieldValue = e( html_entity_decode( $postData[ $field['name'] ]['value']  ) );
            } else {
                $fieldValue = null;
            }

            if( !empty( $field['name'] ) ) {
                $outputFull[ $field['name'] ] = array_merge( $field, [ 'value' => $fieldValue ] );
            }

            $output[ $field['name'] ] = $fieldValue;

        }

        $output['form_description'] = $formDescription;
        $output['form_alias'] = $formAlias;

        $template = Settings::getTranslatedTemplates('en', App::getLocale(), 'autoreply');

        if( Settings::getTranslated('email_template') ){

            if(View::exists(Settings::getTranslated('email_template')) OR !empty( MailTemplate::listAllTemplates()[Settings::getTranslated('email_template')] ) ) {
                $template = Settings::getTranslated('email_template');
            } else {
                Log::error('SMALL CONTACT FORM: Missing defined email template: ' . Settings::getTranslated('email_template') . '. Default template will be used!');
            }

        }

        /**
         *  Override email template by component property
         *  Language specific template has priority (override non language specific)
         */
        if ( !empty($componentProperties['autoreply_template']) and !empty( MailTemplate::listAllTemplates()[ $componentProperties['autoreply_template'] ] ) ) {
            $template = $componentProperties['autoreply_template'];
        } elseif ( !empty($componentProperties['autoreply_template']) and empty( MailTemplate::listAllTemplates()[ $componentProperties['autoreply_template'] ] ) ) {
            Log::error('SMALL CONTACT FORM: Missing defined email template: ' . $componentProperties['autoreply_template'] . '. ' . $template . ' template will be used!');
        }

        if ( !empty($componentProperties[ ('autoreply_template_'.App::getLocale())]) and !empty( MailTemplate::listAllTemplates()[ $componentProperties[ ('autoreply_template_'.App::getLocale())] ] ) ) {
            $template =  $componentProperties[('autoreply_template_'.App::getLocale())];
        } elseif ( !empty($componentProperties[ ('autoreply_template_'.App::getLocale())]) and empty( MailTemplate::listAllTemplates()[ $componentProperties[ ('autoreply_template_'.App::getLocale())] ] ) ) {
            Log::error('SMALL CONTACT FORM: Missing defined email template: ' . $componentProperties[ ('autoreply_template_'.App::getLocale())] . '. ' . $template . ' template will be used!');
        }
        
        if(!empty($messageObject->uploads))
        {
            $uploads = $messageObject->uploads;
        }
        else
        {
            $uploads = [];
        }

        Mail::{$method}($template, ['messageObject' => $messageObject, 'uploads' => $uploads, 'fields' => $output, 'fieldsDetails' => $outputFull, 'url' => url()->full(), 'form_notes' => $formNotes], function($message) use($sendTo, $componentProperties, $output){
            $message->to($sendTo);

            if (!empty($componentProperties['autoreply_subject'])) {
                $message->subject(Twig::parse($componentProperties['autoreply_subject'],['fields' => $output]));
                
                \App::forgetInstance('parse.twig');
                \App::forgetInstance('twig.environment');

            } elseif (Settings::getTranslated('email_subject')) {
                $message->subject(Twig::parse(Settings::getTranslated('email_subject'), ['fields' => $output]));

                \App::forgetInstance('parse.twig');
                \App::forgetInstance('twig.environment');

            }

            /**
            * From address
            * Component's property can override this
            */
            $fromAddress = null;
            $fromAddressName = null;

            if( Settings::getTranslated('email_address_from') ) {
                $fromAddress = Settings::getTranslated('email_address_from');
                $fromAddressName = Settings::getTranslated('email_address_from_name');
            }

            if( !empty($componentProperties['autoreply_address_from']) ) {
                $fromAddress = $componentProperties['autoreply_address_from'];
            }

            if( !empty($componentProperties['autoreply_address_from_name']) ) {
                $fromAddressName = $componentProperties['autoreply_address_from_name'];
            }

            if( !empty($componentProperties[ ('autoreply_address_from_name_'.App::getLocale()) ]) ) {
                $fromAddressName = $componentProperties[ ('autoreply_address_from_name_'.App::getLocale()) ];
            }

            $validator = Validator::make(['email' => $fromAddress], ['email' => 'required|email']);

            if($validator->fails()){
                Log::error('SMALL CONTACT FORM ERROR: Autoreply email address is invalid (' .$fromAddress. ')! System email address and name will be used.');
            } else {
                $message->from($fromAddress, $fromAddressName);
            }


            /**
            * Reply To address
            * Component's property can override this
            */
            $replyToAddress = null;

            if( Settings::getTranslated('email_address_replyto') ) {
                $replyToAddress = Settings::getTranslated('email_address_replyto');
            }

            if( !empty($componentProperties['autoreply_address_replyto']) ) {
                $replyToAddress = $componentProperties['autoreply_address_replyto'];
            }

            if( $replyToAddress ) {

                $validator = Validator::make(['email' => $replyToAddress], ['email' => 'required|email']);

                if($validator->fails()){
                    Log::error('SMALL CONTACT FORM ERROR: Autoreply Reply To email address is invalid (' .$replyToAddress. ')! No Reply To header will be added.');
                } else {
                    $message->replyTo($replyToAddress);
                }

            }
        });

    }

    /**
     * Build and send notification message
     */
    public function sendNotificationEmail($postData, $componentProperties, $formAlias, $formDescription, $messageObject, $formNotes){

        if(!Settings::getTranslated('allow_notifications')) {
            return;
        }

        if(!empty($componentProperties['disable_notifications'])) {
            return;
        }

        $sendTo =  (!empty($componentProperties['notification_address_to']) ? $componentProperties['notification_address_to'] : Settings::getTranslated('notification_address_to') );

        $sendToAddresses = explode(',', $sendTo);        
        $sendToAddressesValidated = [];

        foreach($sendToAddresses as $sendToAddress) {

            $validator = Validator::make(['email' => trim($sendToAddress)], ['email' => 'required|email']);
    
            if($validator->fails()){
                Log::error('SMALL CONTACT FORM ERROR: Notification email address (' .trim($sendToAddress). ') is invalid! No notification will be delivered!');
            } else {
                $sendToAddressesValidated[] = trim($sendToAddress);
            }
        }

        if( !count($sendToAddressesValidated) ) {
            return;
        }

        if( Settings::getTranslated('allow_email_queue') ){
            $method = 'queue';
        } else {
            $method = 'send';
        }

        $output = [];
        $outputFull = [];
        $formFields = Settings::getTranslated('form_fields');
        $replyToAddress = null;
        $replyToName = null;

        foreach($formFields as $field) {

            if(!empty($field['type'] and $field['type'] == 'file')) {
                continue;
            }

            $fieldValue = null;

            if( !empty( $postData[ $field['name'] ]['value'] ) ) {
                $fieldValue = e( html_entity_decode( $postData[ $field['name'] ]['value']  ) );
            } else {
                $fieldValue = null;
            }

            if( !empty( $field['name'] ) ) {
                $outputFull[ $field['name'] ] = array_merge( $field, [ 'value' => $fieldValue ] );
            }

            // If email field is assigned, prepare for replyTo
            if(empty($replyToAddress) and $field['name'] == Settings::getTranslated('autoreply_email_field') and isset($postData[$field['name']]['value'])){
                $replyToAddress = e( $postData[$field['name']]['value'] );
            }

            // If name field is assigned, prepare for fromAddress
            if(empty($replyToName) and $field['name'] == Settings::getTranslated('autoreply_name_field') and isset($postData[$field['name']]['value'])){
                $replyToName = e( $postData[$field['name']]['value'] );
            }

            $output[ $field['name'] ] = $fieldValue;

        }

        $output['form_description'] = $formDescription;
        $output['form_alias'] = $formAlias;

        $template = Settings::getTranslatedTemplates('en', App::getLocale(), 'notification');

        if( Settings::getTranslated('notification_template') ){

            if(View::exists(Settings::getTranslated('notification_template')) OR !empty( MailTemplate::listAllTemplates()[Settings::getTranslated('notification_template')] ) ) {
                $template = Settings::getTranslated('notification_template');
            } else {
                Log::error('SMALL CONTACT FORM: Missing defined email template: ' . Settings::getTranslated('notification_template') . '. Default template will be used!');
            }

        }

        /**
         *  Override email template by component property
         *  Language specific template has priority (override non language specific)
         */
        if ( !empty($componentProperties['notification_template']) and !empty( MailTemplate::listAllTemplates()[ $componentProperties['notification_template'] ] ) ) {
            $template = $componentProperties['notification_template'];
        } elseif ( !empty($componentProperties['notification_template']) and empty( MailTemplate::listAllTemplates()[ $componentProperties['notification_template'] ] ) ) {
            Log::error('SMALL CONTACT FORM: Missing defined email template: ' . $componentProperties['notification_template'] . '. ' . $template . ' template will be used!');
        }


        if ( !empty($componentProperties[ ('notification_template_'.App::getLocale())]) and !empty( MailTemplate::listAllTemplates()[ $componentProperties[ ('notification_template_'.App::getLocale())] ] ) ) {
            $template =  $componentProperties[('notification_template_'.App::getLocale())];
        } elseif ( !empty($componentProperties[ ('notification_template_'.App::getLocale())]) and empty( MailTemplate::listAllTemplates()[ $componentProperties[ ('notification_template_'.App::getLocale())] ] ) ) {
            Log::error('SMALL CONTACT FORM: Missing defined email template: ' . $componentProperties[ ('notification_template_'.App::getLocale())] . '. ' . $template . ' template will be used!');
        }
        
        if(!empty($messageObject->uploads))
        {
            $uploads = $messageObject->uploads;
        }
        else
        {
            $uploads = [];
        }

        Mail::{$method}($template, ['messageObject' => $messageObject, 'uploads' => $uploads, 'fields' => $output, 'fieldsDetails' => $outputFull, 'url' => url()->full(), 'form_notes' => $formNotes], function($message) use($sendToAddressesValidated, $replyToAddress, $replyToName, $componentProperties, $output){

            if( count($sendToAddressesValidated)>1 ) {
                
                foreach($sendToAddressesValidated as $address) {
                    $message->bcc($address);
                }
            } elseif( !empty($sendToAddressesValidated[0]) ) {
                $message->to($sendToAddressesValidated[0]);
            } else {
                return;
            }

            if (!empty($componentProperties['notification_subject'])) {
                $message->subject(Twig::parse($componentProperties['notification_subject'], ['fields' => $output]));

                \App::forgetInstance('parse.twig');
                \App::forgetInstance('twig.environment');
            }

            /**
            *   Set Reply to address and also set From address if requested
            */
            if ( !empty($replyToAddress) ) {

                $validator = Validator::make(['email' => $replyToAddress], ['email' => 'required|email']);

                if($validator->fails()){
                    Log::error('SMALL CONTACT FORM ERROR: Notification replyTo address is not valid (' .$replyToAddress. ')! Reply to address will not be used.');
                    return;
                }

                $message->replyTo($replyToAddress, $replyToName);

                // Force From field if requested
                if ( Settings::getTranslated('notification_address_from_form') ) {
                    $message->from($replyToAddress, $replyToName);
                }
            }

            /**
             * Set From address if defined in component property
             */
            if ( !empty($componentProperties['notification_address_from'])) {

                if (!empty($componentProperties['notification_address_from_name'])) {
                    $fromAddressName = $componentProperties['notification_address_from_name'];
                } else {
                    $fromAddressName = null;
                }

                $message->from($componentProperties['notification_address_from'], $fromAddressName);
            }

        });
    }

    /**
     * Test how many times was given IP address used this day
     * @return int
     */
    public function testIPAddress($ip){

        $today = Carbon::today();

        $count = Message::whereDate('created_at', '=', $today->toDateString())
                        ->where('remote_ip', '=', $ip)
                        ->count();

        return $count;

    }

}
