import React, {useCallback, useEffect, useImperativeHandle, useRef } from "react";
import { useSelector } from "react-redux";
import { useParams } from "react-router";
import { getStyleObjectFromString, processIncludeVariables } from "../..";
import { booleanString, readHotkeyProp, useHotkeys, useReactorNavigation, useWebAuthn, uuid } from "../../_core";
import { getFormData } from "../data/FormExt";
import isEqual from "react-fast-compare";
/**
* @typedef {"menu" | "modal" | "navigate" | "redirect" | "frame" | "operation" | "variable" | "operation_on_dialog"} Reactor.Components.Navigation.TargetType Establece el lugar donde se va a renderizar el resultado de una operación
**/
/**
* Componente que renderiza html link que al ser clickeado ejecuta una acción definida en las propiedades del mismo
* @name Reactor.Components.Navigation.ReactorLink
* @param {string} href Nombre de la operación que va a llamar para recibir el objeto de construccion, o nombre de la variable (cuando target fuera "variable")
* @param {string} href_external Link externo que se va a llamar en una nueva ventana/pestaña del explorador
* @param {string} hotkeys tecla o combinacion que ejecutara el evento click de este componente, se pueden usar varias entradas separando por espacio, las combinaciones se pueden hacer con las teclas ctrl, shift, alt y meta, por ej: hotkeys="ctrl+shift+k" (registra evento control + shift + K) hostkeys="ctrl+d ctrl+h" (registra eventos control + D o control + H)
* @param {string} data Json string con la data que se envía a la operación
* @param {string} include_variables Lista de variables que se incluyen en data (separadas por espacio)
* @param {string} context Contexto contenedor de las variables que se van a incluir, es requerido si se incluyen variables
* @param {Reactor.Components.Navigation.TargetType} target Determina el lugar donde se va a mostrar el resultado de la operación establecida en href
* @param {Reactor.Components.Surfaces.DirectionType} direction Determina la dirección en la que se muestra el menú (solo cuando es target es menú) , "bottom" por defecto
* @param {string} offcanvas_class Establece la clase o clases que va a usar el menú (solo cuando target es menú)
* @param {string} style Estilos para el link
* @param {BooleanString} include_form Incluye la data del form que contiene al componente
* @param {BooleanString} close_menu Establece si se cierra el menu cuando el servidor redirige el target a un modal
* @param {BooleanString} clear_token Establece si se elimina el token antes de llamar a la operacion. Default "false"
* @param {BooleanString} [disabled = "false"] Establece si el componente responde al evento click
* @param {BooleanString} [webauthn_check = "false"] Establece si debe requerir autenticacion por medio de webauthn para ejecutar el evento click
* @class
* @example
<a href="NombreOperacion" data='{"param": "value"}'>Link que dispara un menu</a>
<a href="NombreOperacion" data='{"param": "value"}' target="modal">Link que dispara un modal</a>
<a href="NombreOperacion" href_external="http://www.google.com.ar" data='{"param": "value"}' target="modal">Link que abre Google en una ventana, y ejecuta la operación NombreOperacion que se renderiza ene un modal</a>
*/
export const ReactorLink = React.forwardRef(({variable, disabled = "false", href = "", href_external = null, target = "menu", data = false, navOptions, children, direction = "bottom", className = "", offcanvas_class, style, include_form = "false", include_variables, context, class_name, close_menu, clear_token, webauthn_check = "false", hotkeys, ...attribs}, refReactorLink) => {
const page = useParams().page;
const isActive = page === href;
const ref = useRef();
const variablesState = useSelector(state => context === "_" ? state.app.variables : state.app.variables[context]) || null;
const { execute } = useReactorNavigation({data, navOptions, target, to: href, direction, offcanvasClass: offcanvas_class, useClearToken: clear_token === "true", variable, context});
const { assertionCheck } = useWebAuthn();
const { register, unregister } = useHotkeys();
const execClick = useCallback((event) => {
if(booleanString(disabled) || href === "_"){
return false;
}
const formData = booleanString(include_form) ? {form: getFormData(ref.current.closest("form"))} : {};
//console.log({include_form, formData, form: ref.current.closest("form")})
const variablesData = context && processIncludeVariables({variablesState, include_variables});
execute({...formData, ...variablesData});
}, [disabled, href, include_form, context, include_variables, execute]);
const handleClick = useCallback((event) => {
event?.preventDefault && event?.preventDefault();
event?.stopPropagation && event?.stopPropagation();
if(booleanString(webauthn_check)){
assertionCheck()
.then(()=>{
execClick(event);
})
.catch(()=>{});
}else{
execClick(event);
}
}, [execClick, assertionCheck, webauthn_check])
const handleClickExternal = (event) => {
event?.preventDefault && event?.preventDefault();
event?.stopPropagation && event?.stopPropagation();
if(booleanString(disabled) || !href){
return;
}
execute();
}
useImperativeHandle(refReactorLink, () => {
return {
click: (e) => {
handleClick(e);
}
};
}, [handleClick]);
useEffect(()=>{
if(hotkeys){
const eventos = readHotkeyProp(hotkeys);
const guid = uuid();
register({callback: handleClick, events: eventos, guid});
return () => {
unregister(guid);
}
}
}, [hotkeys]);
return (
<>
{href_external
? <a {...attribs} style={style ? getStyleObjectFromString(style) : {}} href={href_external} className={className || class_name} target="_blank" onClick={handleClickExternal} >{ children }</a>
: <a ref={ref} {...attribs} style={style ? getStyleObjectFromString(style) : {}} className={isActive ? (className || class_name) + " active-nav" : (className || class_name)} href="#" onClick={handleClick} >{ children }</a>
}
</>
)
})