<?php

use dokuwiki\Extension\ActionPlugin;
use dokuwiki\Extension\EventHandler;
use dokuwiki\Extension\Event;
use dokuwiki\plugin\recommend\MenuItem;
use dokuwiki\Form\Form;
use dokuwiki\Utf8\PhpString;

class action_plugin_recommend extends ActionPlugin
{
    public function register(EventHandler $controller)
    {
        foreach (['ACTION_ACT_PREPROCESS', 'AJAX_CALL_UNKNOWN', 'TPL_ACT_UNKNOWN'] as $event) {
            $controller->register_hook($event, 'BEFORE', $this, 'handle');
        }
        $controller->register_hook('MENU_ITEMS_ASSEMBLY', 'AFTER', $this, 'handleMenu');
        $controller->register_hook('AJAX_CALL_UNKNOWN', 'BEFORE', $this, 'autocomplete');
    }

    /**
     * Main processing
     *
     * @param Event $event
     * @return void
     */
    public function handle(Event $event)
    {
        if ($event->data !== 'recommend') {
            return;
        }

        $event->preventDefault();

        if ($event->name === 'ACTION_ACT_PREPROCESS') {
            return;
        }

        $event->stopPropagation();

        global $INPUT;

        // early output to trigger display msgs even via AJAX.
        echo ' ';
        tpl_flush();
        if ($INPUT->server->str('REQUEST_METHOD') === 'POST') {
            try {
                $this->handlePost();
                if ($event->name === 'AJAX_CALL_UNKNOWN') {
                    $this->ajaxSuccess(); // To signal success to AJAX.
                } else {
                    msg($this->getLang('thanks'), 1);
                }
                return; // we're done here
            } catch (\Exception $e) {
                msg($e->getMessage(), -1);
            }
        }

        echo $this->getForm();
    }

    /**
     * Page menu item
     *
     * @param Event $event
     * @return void
     */
    public function handleMenu(Event $event)
    {
        if ($event->data['view'] !== 'page') return;
        // menu item is only for logged in users
        if (empty($_SERVER['REMOTE_USER'])) return;

        array_splice($event->data['items'], -1, 0, [new MenuItem()]);
    }

    /**
     * Autocomplete
     * @param Event $event
     * @throws Exception
     * @author Andreas Gohr
     */
    public function autocomplete(Event $event)
    {

        if ($event->data !== 'plugin_recommend_ac') {
            return;
        }

        $event->preventDefault();
        $event->stopPropagation();

        /** @var \DokuWiki_Auth_Plugin $auth */
        global $auth;
        global $INPUT;

        if (!$auth->canDo('getUsers')) {
            throw new Exception('The user backend can not search for users');
        }

        header('Content-Type: application/json');

        // check minimum length
        $lookup = trim($INPUT->str('search'));
        if (PhpString::strlen($lookup) < 3) {
            echo json_encode([]);
            return;
        }

        // find users by login and name
        $logins = $auth->retrieveUsers(0, 10, ['user' => $lookup]);
        if (count($logins) < 10) {
            $logins = array_merge($logins, $auth->retrieveUsers(0, 10, ['name' => $lookup]));
        }

        // reformat result for jQuery UI Autocomplete
        $users = [];
        foreach ($logins as $login => $info) {
            $users[] = [
                'label' => $info['name'] . ' [' . $login . ']',
                'value' => $login
            ];
        }

        echo json_encode($users);
    }

    /**
     * Returns rendered form
     *
     * @return string
     */
    protected function getForm()
    {
        global $INPUT;

        $id = cleanID(getID()); // we may run in AJAX context, pathcomponent must be converted to pure namespace
        if ($id === '') throw new \RuntimeException('No ID given');

        $form = new Form([
            'action' => wl($id, ['do' => 'recommend'], false, '&'),
            'id' => 'plugin__recommend',
        ]);
        $form->setHiddenField('id', $id); // we need it for the ajax call

        /** @var helper_plugin_recommend_assignment $helper */
        $helper = plugin_load('helper', 'recommend_assignment');
        $template = $helper->loadMatchingTemplate();

        if ($INPUT->server->has('REMOTE_USER')) {
            global $USERINFO;
            $form->setHiddenField('s_name', $USERINFO['name']);
            $form->setHiddenField('s_email', $USERINFO['mail']);
        } else {
            $form->addTextInput('s_name', $this->getLang('yourname'))->addClass('edit');
            $form->addTextInput('s_email', $this->getLang('youremailaddress'))->addClass('edit');
        }

        $form->addTextInput('r_email', $this->getLang('recipients'))
            ->addClass('edit')
            ->val($template['user'] ?? '');
        $form->addTextInput('subject', $this->getLang('subject'))
            ->addClass('edit')
            ->val($template['subject'] ?? '');
        $form->addTextarea('comment', $this->getLang('message'))
            ->attr('rows', '8')
            ->attr('cols', '40')
            ->addClass('edit')
            ->val($template['message'] ?? '');

        /** @var helper_plugin_captcha $captcha */
        $captcha = plugin_load('helper', 'captcha');
        if ($captcha) $form->addHTML($captcha->getHTML());

        $form->addTagOpen('div')->addClass('buttons');
        $form->addButton('submit', $this->getLang('send'))->attr('type', 'submit');
        $form->addTagClose('div');

        return $form->toHTML();
    }

    /**
     * Handles form submission
     *
     * @throws Exception
     */
    protected function handlePost()
    {
        global $INPUT;

        if (!checkSecurityToken()) {
            throw new \Exception('Security token did not match');
        }

        /** @var helper_plugin_recommend_mail $mailHelper */
        $mailHelper = plugin_load('helper', 'recommend_mail');

        // Captcha plugin
        $captcha = null;
        if (@is_dir(DOKU_PLUGIN . 'captcha')) $captcha = plugin_load('helper', 'captcha');
        if (!is_null($captcha) && $captcha->isEnabled() && !$captcha->check()) {
            throw new \Exception($this->getLang('err_captcha'));
        }

        /* Validate input */
        $recipients = $INPUT->str('r_email');

        if (empty($recipients)) {
            throw new \Exception($this->getLang('err_recipient'));
        }

        $recipients = $mailHelper->resolveRecipients($recipients);
        $recipients = implode(',', $recipients);

        if (!isset($_POST['s_email']) || !mail_isvalid($_POST['s_email'])) {
            throw new \Exception($this->getLang('err_sendermail'));
        }
        if (!isset($_POST['s_name']) || trim($_POST['s_name']) === '') {
            throw new \Exception($this->getLang('err_sendername'));
        }
        $s_name = $_POST['s_name'];

        global $conf;

        if (!$this->getConf('usewikimail')) {
          $sender = $s_name . ' <' . $_POST['s_email'] . '>';
        }
        if ($this->getConf('usewikimail')) {
          $sender = $conf['title'] . ' <' . $conf['mailfrom'] . '>';
        }

        $id = $INPUT->filter('cleanID')->str('id');
        if ($id === '' || !page_exists($id)) throw new \Exception($this->getLang('err_page'));

        $comment = $INPUT->str('comment');

        $replacements = [
            'PAGE' => noNS($id),
            'SITE' => $conf['title'],
            'URL'  => wl($id, '', true),
            'COMMENT' => $comment,
            'AUTHOR' => $s_name
        ];

        $mailHelper->sendMail($recipients, $sender, $replacements);

        /** @var helper_plugin_recommend_log $log */
        $log = new helper_plugin_recommend_log(date('Y-m'));
        $log->writeEntry($id, $sender, $recipients, $comment);
    }

    /**
     * show success message in ajax mode
     */
    protected function ajaxSuccess()
    {
        echo '<form id="plugin__recommend" accept-charset="utf-8" method="post" action="?do=recommend">';
        echo '<div class="no">';
        echo '<span class="ui-icon ui-icon-circle-check" style="float: left; margin: 0 7px 50px 0;"></span>';
        echo '<p>' . $this->getLang('done') . '</p>';
        echo '<button type="reset" class="button">' . $this->getLang('close') . '</button>';
        echo '</div>';
        echo '</form>';
    }
}
