import React, { useState, useEffect } from 'react';
import PropTypes from 'prop-types';
import {
  equals,
  complement,
  isEmpty,
  propEq,
  any,
  path,
  pipe,
  not,
  map,
  defaultTo,
  prop,
} from 'ramda';

import { getComponentTestId } from 'utils/test-utils';
import { nodePropTypes } from 'models';
import { isEnterKey } from 'utils/event';
import Button from '../Button';
import styles from './styles.css';

const isNotEmpty = complement(isEmpty);
const getNodeDescription = pipe(prop('description'), defaultTo(''));
const pathTargetValue = path(['target', 'value']);
const onEnterKeyUp = func => event => isEnterKey(event) && func();

const hasNodeWithName = (nodes, name) => any(propEq('id', name), nodes);
const isValidNodeName = (nodes, name) => isNotEmpty(name) && not(hasNodeWithName(nodes, name));

const onChangeHandler = setValue => pipe(pathTargetValue, setValue);
const executeFunctions = (...functions) => map(func => func(), functions);

const PropertiesNode = ({
  onEditNodeStates,
  onEditNodeCpt,
  onChangeNodeName,
  onChangeNodeDescription,
  nodes,
  node,
}) => {
  const { id } = node;
  const nodeDescription = getNodeDescription(node);
  const [name, setName] = useState(id);
  const [description, setDescription] = useState(nodeDescription);
  const hasNoChanges = equals(id, name) && equals(nodeDescription, description);
  const onSaveNodeName = () => isValidNodeName(nodes, name) && onChangeNodeName(node, name);
  const onSaveNodedescription = () => onChangeNodeDescription(node, description);
  const onSaveAll = () => executeFunctions(onSaveNodedescription, onSaveNodeName);
  const onEditStates = () => onEditNodeStates(node);
  const onEditCpt = () => onEditNodeCpt(node);

  useEffect(() => {
    setName(id);
    setDescription(nodeDescription);
  }, [node]);

  return (
    <div data-testid={getComponentTestId('PropertiesNode')}>
      <h2>Propriedades da Variável</h2>

      <div className={styles.fieldWrapper}>
        <label htmlFor="name">
          Nome
          <input
            id="name"
            type="text"
            value={name}
            onChange={onChangeHandler(setName)}
            onKeyUp={onEnterKeyUp(onSaveNodeName)}
          />
        </label>
      </div>

      <div className={styles.fieldWrapper}>
        <label htmlFor="description">
          Descrição
          <textarea
            id="description"
            value={description}
            onChange={onChangeHandler(setDescription)}
          />
        </label>
      </div>

      <div className={styles.fieldWrapper}>
        <Button className={styles.button} onClick={onEditStates} name="editStates">
          Editar estados
        </Button>
      </div>

      <div className={styles.fieldWrapper}>
        <Button className={styles.button} onClick={onEditCpt} name="editProbabilities">
          Editar probabilidades
        </Button>
      </div>

      <div className={styles.fieldWrapper}>
        <Button className={styles.button} onClick={onSaveAll} name="save" disabled={hasNoChanges}>
          Salvar alterações
        </Button>
      </div>
    </div>
  );
};

PropertiesNode.propTypes = {
  node: nodePropTypes.isRequired,
  onEditNodeStates: PropTypes.func.isRequired,
  onEditNodeCpt: PropTypes.func.isRequired,
  nodes: PropTypes.arrayOf(nodePropTypes).isRequired,
  onChangeNodeDescription: PropTypes.func.isRequired,
  onChangeNodeName: PropTypes.func.isRequired,
};

export default PropertiesNode;

@@ -28,16 +28,29 @@
 seEffect
+, useCallback
  %7D from 
@@ -152,15 +152,8 @@
 Eq,%0A
-  any,%0A
   pa
@@ -168,22 +168,8 @@
 pe,%0A
-  not,%0A  map,%0A
   de
@@ -185,16 +185,39 @@
   prop,%0A
+  both,%0A  not,%0A  none,%0A
 %7D from '
@@ -470,16 +470,56 @@
 Empty);%0A
+const isNotEquals = complement(equals);%0A
 const ge
@@ -705,30 +705,36 @@
 %0Aconst hasNo
+No
 deWith
+This
 Name = (node
@@ -734,26 +734,27 @@
 = (n
-odes, name
+ame, nodes
 ) =%3E 
-any
+none
 (pro
@@ -806,78 +806,47 @@
 e = 
-(nodes, name) =%3E isNotEmpty(name) && not(
+both(isNotEmpty, 
 hasNo
+No
 deWith
-Name(nodes, n
+ThisN
 ame)
-)
 ;%0A%0Ac
@@ -916,83 +916,8 @@
 ue);
-%0Aconst executeFunctions = (...functions) =%3E map(func =%3E func(), functions);
 %0A%0Aco
@@ -1243,24 +1243,32 @@
 nst 
-ha
+i
 sNo
+deId
 Change
-s = e
+d = isNotE
 qual
@@ -1282,13 +1282,51 @@
 ame)
- && e
+;%0A  const isNodeDescriptionChanged = isNotE
 qual
@@ -1370,24 +1370,119 @@
 nst 
-onSaveNodeName =
+hasNoChanges = not(isNodeIdChanged) && not(isNodeDescriptionChanged);%0A  const onSaveNodeName = useCallback(%0A   
  () 
@@ -1505,18 +1505,18 @@
 me(n
-odes, name
+ame, nodes
 ) &&
@@ -1539,24 +1539,54 @@
 e(node, name
+),%0A    %5Bname, node, nodes%5D,%0A  
 );%0A  const o
@@ -1607,16 +1607,33 @@
 iption =
+ useCallback(%0A   
  () =%3E o
@@ -1677,63 +1677,21 @@
 ion)
-;%0A  const onSaveAll = () =%3E executeFunctions(onSaveN
+,%0A    %5Bn
 ode
+, 
 desc
@@ -1701,24 +1701,13 @@
 tion
-, onSaveNodeName
+%5D,%0A  
 );%0A 
@@ -1728,16 +1728,28 @@
 tates = 
+useCallback(
 () =%3E on
@@ -1764,24 +1764,33 @@
 States(node)
+, %5Bnode%5D)
 ;%0A  const on
@@ -1799,16 +1799,28 @@
 itCpt = 
+useCallback(
 () =%3E on
@@ -1836,16 +1836,207 @@
 pt(node)
+, %5Bnode%5D);%0A  const onSaveAll = useCallback(() =%3E %7B%0A    if (isNodeDescriptionChanged) onSaveNodedescription();%0A    if (isNodeIdChanged) onSaveNodeName();%0A  %7D, %5Bname, description, node, nodes%5D)
 ;%0A%0A  use

Refactor `PropertiesNode` with `useCallback`