<?php

class Am_Grid_Filter_Content_ScheduleEmail extends Am_Grid_Filter_Content_Email
{
    protected function applyFilter()
    {
        $query = $this->grid->getDataSource()->getDataSourceQuery();
        parent::applyFilter();
        if ($this->getParam('filter_a'))
        {
            $query->addWhere('schedule_type=?', 'access');
        }
    }
}

class Am_Grid_Action_ScheduleEmailPreview extends Am_Grid_Action_Abstract
{
    public function run()
    {
        if ($this->grid->getRequest()->getParam('preview')) {
            $session = $this->grid->getDi()->session->ns('email_preview');
            echo $session->output;
            exit;
        }
        $f = $this->createForm();
        $f->setDataSources([$this->grid->getCompleteRequest()]);
        echo $this->renderTitle();
        if ($f->isSubmitted() && $f->validate() && $this->process($f))
            return;
        echo $f;
    }

    function process(Am_Form $f)
    {
        $vars = $f->getValue();
        $user = $this->grid->getDi()->userTable->findFirstByLogin($vars['user']);
        if (!$user) {
            [$el] = $f->getElementsByName('user');
            $el->setError(___('User %s not found', $vars['user']));
            return false;
        }

        $template = $this->grid->getRecord();
        $mail = Am_Mail_Template::createFromEmailTemplate($template);
        $mail->setUser($user);
        $mail->send($user, new Am_Mail_Transport_Null());

        if ($template->format == 'text') {
            printf('<div style="margin-bottom:0.5em;">%s: <strong>%s</strong></div><div style="border:1px solid #2E2E2E; width:100%%"><pre>%s</pre></div>',
                ___('Subject'),
                Am_Html::escape($this->getSubject($mail)),
                Am_Html::escape($mail->getMail()->getBodyText()->getRawContent()));
        } else {
            $session = $this->grid->getDi()->session->ns('email_preview');
            $session->output = $mail->getMail()->getBodyHtml()->getRawContent();
            printf('<div style="margin-bottom:0.5em;">%s: <strong>%s</strong></div><iframe  style="border:1px solid #2E2E2E; width:100%%; height:600px" src="%s"></iframe>',
                ___('Subject'),
                Am_Html::escape($this->getSubject($mail)),
                $this->grid->getDi()->url('default/admin-content/p/scheduleemails', [
                    '_scheduleemails_a'  => 'preview',
                    '_scheduleemails_id' => $this->grid->getRecordId(),
                    '_scheduleemails_preview' => 1,
                ]));
        }
        return true;
    }

    protected function getSubject($mail)
    {
        $subject = $mail->getMail()->getSubject();
        if (strpos($subject, '=?') === 0)
            $subject = mb_decode_mimeheader($subject);
        return $subject;
    }

    protected function createForm()
    {
        $f = new Am_Form_Admin;
        $f->addText('user')
            ->setLabel(___('Enter username of existing user'))
            ->addRule('required');
        $f->addScript()
            ->setScript(<<<CUT
jQuery(function(){
    jQuery("#user-0" ).autocomplete({
        minLength: 2,
        source: amUrl("/admin-users/autocomplete")
    });
});
CUT
        );

        $f->addSaveButton(___('Preview'));
        foreach ($this->grid->getVariablesList() as $k) {
            $kk = $this->grid->getId() . '_' . $k;
            if ($v = @$_REQUEST[$kk])
                $f->addHidden($kk)->setValue($v);
        }
        return $f;
    }
}

class Am_Grid_Action_ScheduleEmailTest extends Am_Grid_Action_Abstract
{
    public function run()
    {
        $f = $this->createForm();
        $f->setDataSources([$this->grid->getCompleteRequest()]);
        echo $this->renderTitle();
        if ($f->isSubmitted() && $f->validate() && $this->process($f)) {
            echo ___("Email has been sent.");
        } else {
            echo $f;
        }
    }

    function process(Am_Form $f)
    {
        $vars = $f->getValue();
        $user = $this->grid->getDi()->userTable->findFirstByLogin($vars['user']);

        $template = $this->grid->getRecord();
        $mail = Am_Mail_Template::createFromEmailTemplate($template);
        $mail->setUser($user);
        $mail->send($vars['email']);

        return true;
    }

    protected function createForm()
    {
        $f = new Am_Form_Admin;
        $f->addText('user')
            ->setLabel(___('Enter username of existing user'))
            ->addRule('required')
            ->addRule('callback', ___('User with such username does not exists'), function($v){
                return (bool)$this->grid->getDi()->userTable->findFirstByLogin($v);
            });
        $f->addScript()
            ->setScript(<<<CUT
jQuery(function(){
    jQuery("#user-0" ).autocomplete({
        minLength: 2,
        source: amUrl("/admin-users/autocomplete")
    });
});
CUT
            );

        $field = $f->addText('email')
            ->setLabel(___("Email Address\nto send test message"));

        $field->addRule('callback', ___('Please enter valid Email'), ['Am_Validate', 'email']);
        $field->addRule('required');

        $f->addSaveButton(___('Send Test E-Mail'));
        foreach ($this->grid->getVariablesList() as $k) {
            $kk = $this->grid->getId() . '_' . $k;
            if ($v = @$_REQUEST[$kk])
                $f->addHidden($kk)->setValue($v);
        }
        return $f;
    }
}

class Am_Grid_Editable_Scheduleemails extends Am_Grid_Editable_Content
{
    public function init()
    {
        $this->comment = 'Schedule email will be automatically sent at entered day/hour.
Schedule email will not be sent if:
<ul>
    <li>User has unsubscribed from e-mail messages</li>
</ul>';
        parent::init();
        $this->addCallback(self::CB_VALUES_FROM_FORM, [$this, '_valuesFromForm']);
        $this->setFilter(new Am_Grid_Filter_Content_ScheduleEmail);
    }

    protected function createAdapter()
    {
        $ds = new Am_Query(Am_Di::getInstance()->emailTemplateTable);
        $ds->addWhere('name = ?', Bootstrap_ScheduleEmails::NAME);
        $ds->addField("STR_TO_DATE(SUBSTRING_INDEX(schedule, '\n', 1), '%m/%d/%y %k')", "_schedule");
        return $ds;
    }

    public function getSchedule(ResourceAbstract $resource)
    {
        if (!$resource->schedule) {
            return ___('never');
        }

        $_ = array_filter(array_map('trim', explode("\n", $resource->schedule)));
        $r = [];
        $now = new DateTime;
        foreach ($_ as $time) {
            $dt = DateTime::createFromFormat("m/d/y G", $time);

            if ($dt === false)
                continue;

            if ($dt->getTimestamp() < $now->getTimestamp()) {
                $r[] = sprintf('<span style="opacity: .5" title="%s">%s</span>', Am_Html::escape(___('in the past')), $time);
            } else {
                $r[] = sprintf('<span title="%s">%s</span>', Am_Html::escape(___('in the future')), $time);
            }
        }
        return implode('<br/>', $r);
    }

    public function renderSchedule($obj, $fieldName, $controller, $field)
    {
        return $this->renderTd($field->get($obj, $controller), false);
    }

    public function getSchedulePlaceholder($val, ResourceAbstract $resource)
    {
        return ___('%d time moments&hellip;', count(explode(PHP_EOL, $resource->schedule)));
    }

    public function getTriggerPlaceholder($val, ResourceAbstract $resource)
    {
        return ___('%d triggers&hellip;', count(explode(PHP_EOL, trim($val))));
    }

    protected function initGridFields()
    {
        $this->addField('recipient_emails', ___('Recipients'), true, '', [$this, 'getRecipients']);
        $this->addField(new Am_Grid_Field_Expandable('_schedule', ___('Schedule'), true))
            ->setPlaceholder([$this, 'getSchedulePlaceholder'])
            ->setRenderFunction([$this, 'renderSchedule'])
            ->setGetFunction([$this, 'getSchedule'])
            ->setMaxLength(200)
            ->setSafeHtml(true);
        $this->addField('subject', ___('Subject'))->addDecorator(new Am_Grid_Field_Decorator_Shorten(30));
        parent::initGridFields();
        $this->removeField('_link');
        $this->removeField('_access');
        $this->addField(new Am_Grid_Field_Expandable('_access', ___('Trigger'), false))
            ->setPlaceholder([$this, 'getTriggerPlaceholder'])
            ->setRenderFunction([$this, 'renderTrigger'])
            ->setGetFunction([$this, 'getTrigger'])
            ->setMaxLength(200);
    }

    public function initActions()
    {
        parent::initActions();
        $this->actionAdd(new Am_Grid_Action_ScheduleEmailPreview('preview', ___('Preview')));
        $this->actionAdd(new Am_Grid_Action_ScheduleEmailTest('schedule-email-test', ___('Send Test E-Mail')));
        $this->actionAdd(new Am_Grid_Action_Group_Delete());
        $this->actionAdd(new Am_Grid_Action_CopyScheduleEmail);
    }

    public function renderTrigger($obj, $fieldName, $controller, $field)
    {
        return $this->renderTd($field->get($obj, $controller), false);
    }

    public function getTrigger(ResourceAbstract $resource)
    {
        switch ($resource->schedule_type) {
            case 'access' :
                return $this->getProducts($resource);
            case 'search' :
                $_ = $this->getSavedSearchOptions();
                return isset($_[$resource->saved_search_id]) ?
                    sprintf("Search <strong>%s</strong>", $_[$resource->saved_search_id]) :
                    "&mdash;";
        }
    }

    public function getRecipients(EmailTemplate $record)
    {
        $recipients = [];
        if ($record->recipient_user)
            $recipients[] = "<strong>User</strong>";

        if ($record->recipient_aff)
            $recipients[] = "<strong>Affiliate</strong>";

        if ($record->recipient_subusers_parent)
            $recipients[] = "<strong>Subusers Parent</strong>";

        if ($record->recipient_admin)
            $recipients[] = "<strong>Admin</strong>";

        if ($record->recipient_emails)
            $recipients[] = $record->recipient_emails;

        return sprintf('<td>%s</td>', implode(', ', $recipients));
    }

    public function createForm()
    {
        $form = new Am_Form_Admin;

        $name = Bootstrap_ScheduleEmails::NAME;

        $form->addHidden('name', ['value' => Bootstrap_ScheduleEmails::NAME]);

        $form->addStatic()->setContent(nl2br($this->comment))->setLabel(___('Description'));

        $form->addStatic()->setLabel(___('E-Mail Type'))->setContent($name);

        if ($options = $this->getDi()->emailTemplateLayoutTable->getOptions()) {
            $form->addSelect('email_template_layout_id')
                ->setLabel(___('Layout'))
                ->loadOptions([''=>___('No Layout')] + $options);
        }

        $form->addSelect('reply_to')
            ->loadOptions($this->getReplyToOptions())
            ->setLabel(___("Reply To\n" .
                "mailbox for replies to message"));

        $recipient = $form->addGroup(null)->setLabel(___('Recipients'));
        $recipient->setSeparator('<br />');
        $recipient->addAdvCheckbox('recipient_user')
            ->setContent(___('User Email'));
        if ($this->getDi()->modules->isEnabled('aff')) {
            $recipient->addAdvCheckbox('recipient_aff')
                ->setContent(___('Affiliate Email'));
        }
        if ($this->getDi()->modules->isEnabled('subusers')) {
            $recipient->addAdvCheckbox('recipient_subusers_parent')
                ->setContent(___('Subusers Parent Email'));
        }
        $recipient->addAdvCheckbox('recipient_admin')
            ->setContent(___('Admin Email'));
        $recipient->addAdvCheckbox('recipient_other', ['id' => 'checkbox-recipient-other'])
            ->setContent(___('Other'));

        $form->addText('recipient_emails', ['class' => 'am-el-wide', 'id' => 'input-recipient-emails', 'placeholder' => ___('Email Addresses Separated by Comma')])
            ->setLabel(___('Emails'))
            ->addRule('callback2', ___('Please enter valid e-mail addresses'), [$this, 'validateOtherEmails']);

        $form->addText('bcc', ['class' => 'am-el-wide', 'placeholder' => ___('Email Addresses Separated by Comma')])
            ->setLabel(___("BCC\n" .
                "blind carbon copy allows the sender of a message to conceal the person entered in the Bcc field from the other recipients"))
            ->addRule('callback', ___('Please enter valid e-mail addresses'), ['Am_Validate', 'emails']);

        $form->addScript()->setScript(<<<CUT
jQuery("#checkbox-recipient-other").change(function(){
    jQuery("#row-input-recipient-emails").toggle(this.checked);
}).change();
CUT
            );

        $form->addElement(new Am_Form_Element_MailEditor($name, ['upload-prefix' => EmailTemplate::ATTACHMENT_AUTORESPONDER_EXPIRE_FILE_PREFIX]));
        $access_desc = ___('Send E-Mail if customer has subscription (required)');

        $form->addAdvRadio('schedule_type')
            ->setLabel(___('Condition Type'))
            ->loadOptions([
                'access' => ___('Access Permissions'),
                'search' => ___('Saved Search')
            ]);

        $form->addSelect('saved_search_id')
            ->setLabel('Saved Search')
            ->loadOptions($this->getSavedSearchOptions());

        $form->addElement(new Am_Form_Element_ResourceAccess('_access'))
            ->setLabel($access_desc)
            ->setAttribute('without_period', true)
            ->setAttribute('without_free_without_login', true)
            ->setAttribute('without_user_group_id', true);

        $group = $form->addGroup()
                ->setLabel(___('Send E-Mail only if customer has no subscription (optional)'));
        $group->setSeparator('<br />');

        if ($this->getDi()->modules->isEnabled('newsletter')) {
            $form->addMagicselect('_schedule_newsletters')
                ->setLabel(___('Send E-Mail only if customer subscribed to selected newsletter threads(optional)'))
                ->loadOptions($this->getDi()->newsletterListTable->getAdminOptions());
        }
        $select = $group->addMagicSelect('_not_conditions', ['class'=>'am-combobox']);
        $this->addCategoriesProductsList($select);
        $group->addAdvCheckbox('not_conditions_expired')->setContent(___('check expired subscriptions too'));
        $group->addAdvCheckbox('not_conditions_future')->setContent(___('check future subscriptions too'));

        $form->addScript()
            ->setScript(<<<CUT
jQuery(function(){
    jQuery('[name=schedule_type]').change(function(){
        jQuery('.resourceaccess, [data-name^=_not_conditions]').closest('.row, .am-row').toggle(jQuery('[name=schedule_type]:checked').val() == 'access');
        jQuery('[name=saved_search_id]').closest('.row, .am-row').toggle(jQuery('[name=schedule_type]:checked').val() == 'search');
    }).change();
});
CUT
            );

        $gr = $form->addGroup()
            ->setLabel("Schedule\n" .
                'Date and time format MM/DD/YY HH
                MM - month, DD - day, YY - year, HH - hour in 24hr format
                for example
                03/24/17 9
                12/31/17 19');

        $l = ___('Current Server Date and Time');
        $d = date('m/d/y H', $this->getDi()->time);

        $gr->addTextarea('schedule', ['class'=>'one-per-line']);
        $gr->addHtml()->setHtml("<br /><div>$l: <strong>$d</strong></div>");

        return $form;
    }

    protected function getSavedSearchOptions()
    {
        return $this->getDi()->db->selectCol("SELECT saved_search_id as ARRAY_KEY, name
            FROM ?_saved_search WHERE class=?", 'Am_Query_User');
    }

    protected function getReplyToOptions()
    {
        $op = [];
        $op[''] = sprintf('%s <%s>',
            $this->getDi()->config->get('admin_email_name', $this->getDi()->config->get('site_title')),
            $this->getDi()->config->get('admin_email_from', $this->getDi()->config->get('admin_email')));
        foreach ($this->getDi()->adminTable->findBy() as $admin) {
           $op[$admin->pk()] = sprintf('%s <%s>', $admin->getName(), $admin->email);
        }
        return $op;
    }

    function validateOtherEmails($val, $el)
    {
        $vars = $el->getContainer()->getValue();
        if ($vars['recipient_other'] == 1) {
            if (!strlen($vars['recipient_emails']))
                return ___('Please enter one or more email');
            if (!Am_Validate::emails($val))
                return ___('Please enter valid e-mail addresses');
        }
    }

    function addCategoriesProductsList(HTML_QuickForm2_Element_Select $select)
    {
        $g = $select->addOptgroup(___('Product Categories'), ['class' => 'product_category_id', 'data-text' => ___("Category")]);
        $g->addOption(___('Any Product'), 'c-1', ['style' => 'font-weight: bold']);
        foreach ($this->getDi()->productCategoryTable->getAdminSelectOptions() as $k => $v) {
            $g->addOption($v, 'c' . $k);
        }
        $g = $select->addOptgroup(___('Products'), ['class' => 'product_id', 'data-text' => ___("Product")]);
        foreach ($this->getDi()->productTable->getOptions() as $k => $v) {
            $g->addOption($v, 'p' . $k);
        }
    }

    public function _valuesToForm(array &$values, Am_Record $record)
    {
        parent::_valuesToForm($values, $record);
        $values['attachments'] = explode(',', @$values['attachments']);
        $values['_not_conditions'] = explode(',', @$values['not_conditions']);
        $values['_schedule_newsletters'] = explode(',', @$values['schedule_newsletters']);

        if (!empty($values['recipient_emails'])) {
            $values['recipient_other'] = 1;
        }

        if (empty($values['schedule_type'])) {
            $values['schedule_type'] = 'access';
        }

        if (!$record->isLoaded()) {
            $values['recipient_user'] = 1;
            $values['format'] = 'html';
        }
    }

    public function _valuesFromForm(array &$values)
    {
        if (!$values['reply_to']) {
            $values['reply_to'] = null;
        }
        if (!$values['email_template_layout_id']) {
            $values['email_template_layout_id'] = null;
        }

        $values['attachments'] = implode(',', @$values['attachments']);
        $values['_not_conditions'] = array_filter(array_map('filterId', $values['_not_conditions']));
        $values['not_conditions'] = implode(',', $values['_not_conditions']);
        if ($this->getDi()->modules->isEnabled('newsletter')) {
            $values['schedule_newsletters'] = implode(',', $values['_schedule_newsletters']);
        }

        if (!$values['recipient_other'])
            $values['recipient_emails'] = null;
        unset($values['recipient_other']);

        $_ = array_map('trim', explode(PHP_EOL, $values['schedule']));
        $_ = array_filter($_, function($d) {
            return (DateTime::createFromFormat('m/d/y G', $d)) !== false;
        });
        usort($_, function($a, $b) {
            $a = DateTime::createFromFormat('m/d/y G', $a);
            $b = DateTime::createFromFormat('m/d/y G', $b);

            return $a <=> $b;
        });
        $values['schedule'] = implode(PHP_EOL, $_);
    }
}

class Am_Grid_Action_CopyScheduleEmail extends Am_Grid_Action_Abstract
{
    protected $id = 'copy';
    protected $privilege = 'insert';

    public function run()
    {
        $record = $this->grid->getRecord();

        $vars = $record->toRow();
        unset($vars['email_template_id']);

        $back = @$_SERVER['HTTP_X_REQUESTED_WITH'];
        $_SERVER['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest';
        $controller = new AdminContentController(
            new Am_Mvc_Request(),
            new Am_Mvc_Response(),
            ['di' => Am_Di::getInstance()]
        );

        $this->grid->_valuesToForm($vars, $record);

        $request = new Am_Mvc_Request($vars + [
                '_scheduleemails_a' => 'insert',
                '_scheduleemails_b' => $this->grid->getBackUrl()
            ], Am_Mvc_Request::METHOD_POST);

        $controller->setRequest($request);

        $request->setModuleName('default')
            ->setControllerName('admin-content')
            ->setParam('page_id', 'scheduleemails')
            ->setActionName('index')
            ->setDispatched(true);

        $controller->dispatch('indexAction');
        $response = $controller->getResponse();
        $response->sendResponse();
        $_SERVER['HTTP_X_REQUESTED_WITH'] = $back;
    }
}