<?php

/**
 * @title Sales Popup
 * @am_plugin_api 6.0
 */
class Am_Plugin_SalesNotification extends Am_Plugin
{
    const PLUGIN_STATUS = self::STATUS_PRODUCTION;
    const PLUGIN_COMM = self::COMM_COMMERCIAL;
    const PLUGIN_REVISION = '6.3.43';

    protected $_configPrefix = 'misc.';

    static function getDbXml()
    {
        return <<<CUT
<schema version="4.0.0">
    <table name="user">
        <field name="sales_notification_disabled" type="tinyint" />
    </table>
</schema>
CUT;
    }

    function getTitle()
    {
        return 'Sales Popup';
    }

    function _initSetupForm(Am_Form_Setup $form)
    {
        $form->addTextArea('template', 'class="am-el-wide" rows=10')
            ->setLabel(___("Notification template\n"
                . "You can use these placeholders:\n"
                . "<b>%user.login%</b> - login of user\n"
                . "<b>%user.email%</b> - email of new user\n"
                . "<b>%user.name_f%</b> - First name of user\n"
                . "<b>%user.name_l%</b> - Last name of user\n"
                . "<b>%product_title%</b> - Purchased product title\n"
                . "<b>%time%</b> - How many seconds or minutes ago purchase was made\n"
                . ""));

        $form->addText('period')->setLabel(___("Period in seconds\n"
                . "when sale will be added to notification,\n"
                . " default is to add all sales from past 2 hours"));

        $form->addAdvRadio('sort')
            ->setLabel(___("Sort Order"))
            ->loadOptions([
                'rand' => ___('Random'),
                'dattm_asc' => ___('Chronological'),
                'dattm_desc' => ___('Reverse Chronological'),
            ]);

        $form->addAdvRadio('position')
            ->setLabel('Position')
            ->loadOptions([
                'right top' => 'Right Top',
                'right bottom' => 'Right Bottom',
                'left top' => 'Left Top',
                'left bottom' => 'Left Bottom'
            ]);
        $form->addAdvRadio('animation')
            ->setLabel('Animation')
            ->loadOptions([
                'slideDown:slideUp' => 'Slide',
                'fadeIn:fadeOut' => 'Fade'
            ]);

        $form->addAdvCheckbox('can_close')
            ->setLabel('Allow to hide notification for current site view');

        $form->addScript()
            ->setScript(<<<'CUT'
jQuery(function(){
    jQuery('[name$=period]').keyup(function(){
        let seconds = parseInt(this.value);
        if (isNaN(seconds)) seconds = 0;
        
        let days = parseInt(seconds / (60*60*24));
        let hrs = parseInt((seconds - days * 60*60*24) / (60*60));
        let min = parseInt((seconds - days * 60*60*24 - hrs * 60*60) / 60);
        let sec = seconds - days * 60*60*24 - hrs * 60*60 - min * 60;
        
        let out = [];
        
        if (days > 0) {
            out.push(`${days}d`);
        }
        
        if (hrs > 0) {
            out.push(`${hrs}h`);
        }
        
        if (min > 0) {
            out.push(`${min}m`);
        }
        
        if (sec > 0) {
            out.push(`${sec}s`);
        }
    
        jQuery('#period-preview').remove();
        jQuery(this).after('<span id="period-preview" style="margin-left: 1em">' + out.join(' ') + '</span>');
    }).keyup();
})
CUT
);

        $form->setDefault('animation', 'slideDown:slideUp');
        $form->setDefault('position', 'right top');
        $form->setDefault('template', $this->getDefaultTemplate());
        $form->setDefault('period', 2 * 3600);
        $form->setDefault('sort', 'rand');
    }

    function getDefaultTemplate()
    {
        return 'User %user.name_f% %user.name_l% has purchased "%product_title%" %time%';
    }

    function getLatestPurchaseInfo($product_id = null, $excludes = null)
    {
        $dateTime = $this->getDi()->dateTime;
        $dateTime->modify('-' . $this->getConfig('period', 2 * 3600) . ' seconds');
        $tm = $dateTime->format('Y-m-d H:i:s');

        switch ($this->getConfig('sort', 'rand')) {
            case 'dattm_asc' :
                $sort_order = "p.dattm ASC";
                break;
            case 'dattm_desc' :
                $sort_order = "p.dattm DESC";
                break;
            case 'rand':
            default:
                $sort_order = "RAND()";
        }

        $payments = $this->getDi()->invoicePaymentTable->selectObjects(<<<CUT
            SELECT p.*
                FROM ?_invoice_payment p
                LEFT JOIN ?_invoice_item ii ON p.invoice_id = ii.invoice_id
                WHERE p.dattm > ? { AND  p.invoice_payment_id NOT IN  (?a) }
                { AND ii.item_id in (?a) } ORDER BY $sort_order LIMIT 30
CUT
            , $tm, is_array($excludes) ? $excludes : DBSIMPLE_SKIP, is_null($product_id) || !$product_id ? DBSIMPLE_SKIP : (array)$product_id);
        $data = [];
        foreach ($payments as $payment) {
            $invoice = $payment->getInvoice();
            $time = $this->getDi()->view->getElapsedTime($payment->dattm);
            foreach ($invoice->getItems() as $item) {
                if (is_null($product_id) || in_array($item->item_id, $product_id)) {
                    break;
                }
            }
            $data[] = [
                'user' => $invoice->getUser(),
                'product' => $item->tryLoadProduct(),
                'product_title' => $invoice->getLineDescription(),
                'invoice' => $invoice,
                'payment' => $payment,
                'time' => $time
            ];
        }
        return $data;
    }

    function directAction(/* Am_Mvc_Request */ $request, /* Am_Mvc_Response */ $response, $invokeArgs)
    {
        switch ($request->getParam('action'))
        {
            case 'js' :
                $response->setHeader('Content-Type', 'application/javascript');
                return $this->showJs();
            case 'get' :
                $response->setHeader('Access-Control-Allow-Origin', '*');
                return $this->showNotificationText($response, $request->getParam('product'));
            case 'close' :
                Am_Cookie::set("{$this->getId()}-close", 1);
                $response->ajaxResponse(true);
        }
    }

    function needShow()
    {
        if ($this->getDi()->auth->getUser()
            && $this->getDi()->auth->getUser()->sales_notification_disabled) {

            return false;
        }

        if (!empty($_COOKIE["{$this->getId()}-close"])) {
            return false;
        }

        return true;
    }

    function showNotificationText($response, $product_id)
    {
        if (!$this->needShow()) {
            $response->ajaxResponse([]);
        }

        if ($product_id) {
            $product_id = $this->getDi()->productTable->extractProductIds(array_filter(explode(",", $product_id)));
        }

        $data = [];
        $infos = $this->getLatestPurchaseInfo($product_id ?: null);
        foreach ($infos as $info) {
            $tmpl = new Am_SimpleTemplate();
            $tmpl->assign($info);
            $data[] = $tmpl->render($this->getConfig('template', $this->getDefaultTemplate()));
        }
        $response->ajaxResponse($data);
    }

    function showJs()
    {
        $url = 'https://cdnjs.cloudflare.com/ajax/libs/notify/0.4.2/notify.min.js';
        $jquery = 'https://code.jquery.com/jquery-2.2.4.min.js';
        $ajaxEndpoint = $this->getDi()->surl('misc/sales-notification/get');
        $closeEndpoint = $this->getDi()->surl('misc/sales-notification/close');

        $closeHtml = $this->getConfig('can_close') ? "<span class='am-sale-notify-close' style='float:right; margin: 0 0 .5em 1em'><span class='am-sale-notify-close-glyph'>&#10005;</span></span>" : "";

        $position = json_encode($this->getConfig('position', 'right top'));
        [$showAnimation, $hideAnimation] = array_map('json_encode', explode(':', $this->getConfig('animation', 'slideDown:slideUp')));

        print <<<CUT
(function(){

var init = function(window, document, callback) {
    if (window.jQuery === undefined) {
        var script = document.createElement("script");
        script.type = "text/javascript";
        script.src = "{$jquery}";
        script.crossorigin = "anonymous";
        script.onload = function() {
            callback(window.jQuery);
        };
        (document.getElementsByTagName("head")[0] || document.documentElement).appendChild(script);
    } else {
        callback(window.jQuery);
    }
};
var callback = function()
{
    init(window, document, function($) {
        var script = document.createElement("script");
        script.type = "text/javascript";
        script.src = "{$url}";
        script.crossorigin = "anonymous";
        script.onload = function() {
            getNextInterval = function()
            {
                var i = options.interval;
                if (i && !Number.isInteger(i) && i.indexOf(':')) {
                    var r  = i.split(':');
                    t = (parseInt(r[0]) + Math.random() * (parseInt(r[1])-parseInt(r[0]))) * 1000;
                    return t;
                } else {
                    return i ? i*1000 : 60000;
                }
            }

            var options = jQuery('#am-sale-notify').data();
            options.className = options.className ?  options.className : 'base';
            options.style = 'default';
            options.position = {$position};
            options.showAnimation = {$showAnimation};
            options.hideAnimation = {$hideAnimation};
            options.autoHideDelay = options.autoHideDelay ? (options.autoHideDelay < 1000 ? options.autoHideDelay * 1000 : options.autoHideDelay) : 5000;
            $.notify.addStyle("default", {
                html: "<div>{$closeHtml}<span data-notify-html></span></div>",
                classes: {
                    base: {
                        "background-color": "#fff",
                        "border": "1px solid #bbcddb",
                        "border-radius": "7px",
                        "box-shadow" : "0 0 10px #bbcddb",
                        "max-width": "350px",
                        "padding": "1em",
                    },
                }
            });
            var ndata = [];
            var isActive = true;
            showNotification = function(options){
                if (isActive) {
                    if (ndata.length) {
                        $.notify(ndata.shift(), options);
                        setTimeout(function(){showNotification(options)}, options.autoHideDelay + getNextInterval());
                        return;
                    }
                    $.get('{$ajaxEndpoint}?product=' + (options.product ? options.product : ''), function(data){
                        ndata = data;
                        if(ndata.length) {
                            $.notify(ndata.shift(), options);
                            setTimeout(function(){showNotification(options)}, options.autoHideDelay + getNextInterval());
                        }
                    });
                }
            }
            setTimeout(function(){showNotification(options)}, options.startDelay ? options.startDelay * 1000 : getNextInterval());
            $(document).on('click', '.am-sale-notify-close', function() {
                isActive = false;
                $(this).trigger('notify-hide');
                $.get('{$closeEndpoint}');
            });
        };
        (document.getElementsByTagName("head")[0] || document.documentElement).appendChild(script);
    });
}

if (document.readyState != "loading") {
    callback();
} else {
    document.addEventListener("DOMContentLoaded", callback);
}

})();
CUT;
    }

}

Am_Di::getInstance()->hook->add(Am_Event::LOAD_BRICKS, function(Am_Event $e) {

    class Am_Form_Brick_SalesNotificationDisabled extends Am_Form_Brick
    {
        protected $hideIfLoggedInPossible = self::HIDE_DONT;
        protected $labels = [
            "Disable social proof popup",
        ];

        public function __construct($id = null, $config = null)
        {
            $this->name = ___('Sales Notification Disabled');
            parent::__construct($id, $config);
        }

        public function isAcceptableForForm(Am_Form_Bricked $form)
        {
            return $form instanceof Am_Form_Profile;
        }

        public function insertBrick(HTML_QuickForm2_Container $form)
        {
            $form->addAdvCheckbox('sales_notification_disabled')
                ->setLabel($this->___("Disable social proof popup"));
        }
    }

});