<?php
/**
 * Plugin NICC Custom Login v2.0
 * Reemplaza el formulario de login de DokuWiki con diseño corporativo
 *
 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
 * @author  SIE Asesorías
 */

if (!defined('DOKU_INC')) die();

class action_plugin_nicclogin extends DokuWiki_Action_Plugin {

    /**
     * Registrar eventos
     */
    public function register(Doku_Event_Handler $controller) {
        // Hook para forzar login cuando no hay sesion activa
        $controller->register_hook('ACTION_ACT_PREPROCESS', 'BEFORE', $this, 'forceLogin', array(), 1);
        // Hook para inyectar CSS - prioridad alta
        $controller->register_hook('TPL_METAHEADER_OUTPUT', 'BEFORE', $this, 'addStyles', array(), 1);
        // Hook principal para renderizar login
        $controller->register_hook('TPL_ACT_RENDER', 'BEFORE', $this, 'handleLogin', array(), 1);
        // Hook de respaldo
        $controller->register_hook('TPL_CONTENT_DISPLAY', 'BEFORE', $this, 'handleLoginContent', array(), 1);
    }

    /**
     * Forzar accion login cuando el usuario no esta autenticado
     *
     * IMPORTANTE: No se puede simplemente hacer $event->data = 'login' porque
     * si login falla (ej: $auth no cargado), ActionRouter usa $presetup (que era
     * 'show') como "from" y el fallback tambien es 'show', causando:
     *   transitionAction('show', 'show') → FatalException: Infinite loop
     *
     * Solucion: verificar que $auth esta listo ANTES de forzar login.
     * Si no esta listo, dejamos pasar sin forzar (DokuWiki mostrara su error nativo).
     */
    public function forceLogin(Doku_Event $event, $param) {
        global $conf;
        global $auth;

        // Si ya es accion login, no hacer nada
        if ($event->data === 'login') return;

        // Si el usuario ya esta autenticado, no hacer nada
        if (!empty($_SERVER['REMOTE_USER'])) return;

        // Si es un POST de login (enviando credenciales), no interferir
        if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['u'])) return;

        // Si es accion de recuperar password, no interferir
        if ($event->data === 'resendpwd') return;

        // Si es accion de registro, no interferir
        if ($event->data === 'register') return;

        // SEGURIDAD: Verificar que ACL y auth estan listos antes de forzar login
        // Si no estan listos, Login::checkPreconditions() lanzaria
        // ActionAclRequiredException con fallback 'show', causando loop infinito
        if (empty($conf['useacl'])) return;
        if (!($auth instanceof \dokuwiki\Extension\AuthPlugin)) return;

        // Forzar accion login para usuarios no autenticados
        $event->data = 'login';
    }

    /**
     * Inyectar CSS y fuentes
     */
    public function addStyles(Doku_Event $event, $param) {
        global $ACT;
        if ($ACT !== 'login') return;

        // Google Fonts (carga asincrona no-bloqueante via media="print")
        $event->data['link'][] = array(
            'rel'    => 'preconnect',
            'href'   => 'https://fonts.googleapis.com'
        );
        $event->data['link'][] = array(
            'rel'    => 'preconnect',
            'href'   => 'https://fonts.gstatic.com',
            'crossorigin' => 'anonymous'
        );
        $event->data['link'][] = array(
            'rel'    => 'stylesheet',
            'href'   => 'https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;700&family=Playfair+Display:wght@600;700&display=swap',
            'media'  => 'print',
            'onload' => "this.media='all'"
        );

        // Enlazar style.css del plugin explícitamente
        $event->data['link'][] = array(
            'rel'  => 'stylesheet',
            'type' => 'text/css',
            'href' => DOKU_BASE . 'lib/plugins/nicclogin/style.css?v=' . time()
        );

        // CSS crítico inline como respaldo
        $event->data['style'][] = array(
            'type'  => 'text/css',
            '_data' => $this->getCriticalCSS()
        );
    }

    /**
     * CSS crítico para ocultar elementos de DokuWiki
     *
     * PRIMARIO: Usa .mode_login que DokuWiki agrega server-side via tpl_classes()
     *           en #dokuwiki__top cuando $ACT === 'login'. No depende de JavaScript.
     * RESPALDO: body.do_login es agregado por JS inline como defensa adicional.
     */
    private function getCriticalCSS() {
        return '
            /* Primario: .mode_login generado por PHP (tpl_classes) - sin dependencia de JS */
            .mode_login #dokuwiki__header,
            .mode_login #dokuwiki__aside,
            .mode_login #dokuwiki__footer,
            .mode_login .pageId,
            .mode_login div.breadcrumbs,
            .mode_login #dw__login,
            .mode_login .plugin_loglog,
            .mode_login .dokuwiki__sitetools,
            .mode_login .dokuwiki__usertools { display: none !important; }
            #dokuwiki__top.mode_login { padding: 0 !important; margin: 0 !important; max-width: none !important; }
            .mode_login .wrapper { padding: 0 !important; }
            /* Respaldo JS: body.do_login para #dokuwiki__site (padre de #dokuwiki__top, no alcanzable via .mode_login) */
            body.do_login #dokuwiki__site { padding: 0 !important; margin: 0 !important; max-width: none !important; }
        ';
    }

    /**
     * Manejar el login - Hook principal
     */
    public function handleLogin(Doku_Event $event, $param) {
        global $ACT;
        if ($ACT !== 'login') return;

        $event->preventDefault();
        echo $this->getLoginHTML();
    }

    /**
     * Manejar el login - Hook de respaldo
     */
    public function handleLoginContent(Doku_Event $event, $param) {
        global $ACT;
        if ($ACT !== 'login') return;

        static $rendered = false;
        if ($rendered) return;
        $rendered = true;

        $event->data = $this->getLoginHTML();
    }

    /**
     * Generar HTML del formulario de login
     */
    private function getLoginHTML() {
        global $ID, $MSG;

        $sectok     = getSecurityToken();
        $logo       = DOKU_BASE . 'lib/plugins/nicclogin/images/logo.png';
        $cssFile    = DOKU_BASE . 'lib/plugins/nicclogin/style.css?v=' . time();
        $formAction = wl($ID);
        $resetLink  = wl($ID, array('do' => 'resendpwd'));
        $safeID     = hsc($ID);

        // Mensajes de DokuWiki (con escape XSS)
        $messages = '';
        if (isset($MSG) && is_array($MSG) && count($MSG) > 0) {
            $messages .= '<div class="nicc-messages">';
            foreach ($MSG as $msg) {
                $lvl = isset($msg['lvl']) ? $msg['lvl'] : 'info';
                $cssClass = 'nicc-msg';
                if ($lvl === 'error' || $lvl == -1) {
                    $cssClass .= ' nicc-msg-error';
                } elseif ($lvl === 'success' || $lvl == 1) {
                    $cssClass .= ' nicc-msg-success';
                } else {
                    $cssClass .= ' nicc-msg-info';
                }
                // Escapar mensaje para prevenir XSS
                $msgText = isset($msg['msg']) ? hsc($msg['msg']) : '';
                $messages .= '<div class="' . $cssClass . '">' . $msgText . '</div>';
            }
            $messages .= '</div>';
            $MSG = array();
        }

        // Saludo según hora
        $hour = (int) date('G');
        if ($hour >= 5 && $hour < 12) {
            $saludo = '¡Buenos días!';
        } elseif ($hour >= 12 && $hour < 19) {
            $saludo = '¡Buenas tardes!';
        } else {
            $saludo = '¡Buenas noches!';
        }

        // HTML con CSS inline como respaldo absoluto
        $html = <<<HTML
<link rel="stylesheet" href="{$cssFile}" type="text/css">
<div class="nicc-login-wrapper">
    <div class="nicc-left-panel">
        <div class="nicc-logo-container">
            <img src="{$logo}" alt="SIE Asesorías" onerror="this.style.display='none'">
        </div>
        <div class="nicc-welcome-text">
            <h1>Bienvenido</h1>
            <div class="nicc-decorative-line"></div>
            <p>Sistema integral de gestión de calidad y administración de proyecto y cumplimiento normativo</p>
        </div>
    </div>
    <div class="nicc-right-panel">
        <form action="{$formAction}" method="post" accept-charset="utf-8">
            <input type="hidden" name="sectok" value="{$sectok}">
            <input type="hidden" name="id" value="{$safeID}">
            <input type="hidden" name="do" value="login">

            <div class="nicc-form-header">
                <h2>Iniciar Sesión</h2>
                <p>{$saludo} Ingresa tus credenciales para continuar</p>
            </div>

            {$messages}

            <div class="nicc-form-group" style="--i:0">
                <label for="nicc__user">Usuario</label>
                <input type="text" id="nicc__user" name="u" placeholder="Tu nombre de usuario" autocomplete="username" autofocus required>
            </div>

            <div class="nicc-form-group" style="--i:1">
                <label for="nicc__pass">Contraseña</label>
                <input type="password" id="nicc__pass" name="p" placeholder="Tu contraseña" autocomplete="current-password" required>
            </div>

            <div class="nicc-remember-row">
                <label><input type="checkbox" name="r" value="1"> Recordarme</label>
                <a href="{$resetLink}">¿Olvidaste tu contraseña?</a>
            </div>

            <button type="submit" class="nicc-btn-login">Conectarse</button>

            <div class="nicc-footer-text">NICC &mdash; Powered by <strong>SIE Asesorías</strong></div>
        </form>
    </div>
</div>
<script>
(function() {
    // Respaldo JS: agrega do_login al body para CSS de #dokuwiki__site
    // (El ocultamiento primario usa .mode_login via CSS server-side, no depende de JS)
    document.body.classList.add('do_login');
    // Respaldo directo: ocultar elementos por si CSS falla
    var hide = ['#dokuwiki__header','#dokuwiki__aside','#dokuwiki__footer','#dw__login','.dokuwiki .pageId','.dokuwiki div.breadcrumbs'];
    hide.forEach(function(s) { var e = document.querySelector(s); if (e) e.style.display = 'none'; });
})();
</script>
HTML;
        return $html;
    }
}
