import React, { useCallback, useContext, useEffect, useId, useRef, useState } from 'react';
import addClass from 'reneco-utils/addClass';
import isFoo from 'reneco-utils/isFoo';
import { Context as BlockContext } from './Block';

import './Row.scss';

export default ({
    name,
    className,
    content,
    paddingVertical: pPaddingVertical,
    paddingHorizontal: pPaddingHorizontal,
    align: pAlign,
    color: pColor,
    decoration: pDecoration,
    fontFamily: pFontFamily,
    fontSize: pFontSize,
    fontWeight: pFontWeight,
    fontStyle: pFontStyle,
    icon,
    iconSize: pIconSize,

    onClick,

    onRelationAdd,
    onRelationRemove,
    onRelationChange,

    relatable,
    relations: pRelations
}) => {
    const rowIX = useId(),
        [ix, setIX] = useState(-1),
        [relations, setRelations] = useState(pRelations),
        addRelation = useCallback(target => setRelations(pRelations => (ix => (nState => {
                if(ix < 0) {
                    onRelationAdd && onRelationAdd(target);
                    onRelationChange && onRelationChange(nState || []);
                }
                return nState;
            })(ix < 0 ? (pRelations ? [...pRelations, target]: [target]) : pRelations))((pRelations || []).indexOf(target))), 
        [pRelations]),
        removeRelation = useCallback(target => setRelations(pRelations => (ix => {
            if(ix > -1) {
                pRelations.splice(ix, 1);
                onRelationRemove && onRelationRemove(target);
                onRelationChange && onRelationChange(pRelations.slice());
            }
            return pRelations.slice();
        })((pRelations || []).indexOf(target))), [pRelations]),        
        baseClass = 'reneco-components-scheme-block',
        {
            getRowStyle, 
            registerRow, 
            unregisterRow, 
            updateRow,
            rowsMeta,
            width,
            height,
            borderColor: blockBorderColor,
            borderWidth: blockBorderWidth
        } = useContext(BlockContext),
        $box = useRef(null),
        [hover, setHover] = useState(false),
        onOver = () => setHover(true),
        onLeave = () => setHover(false),
        paddingHorizontal = pPaddingHorizontal || getRowStyle && getRowStyle('paddingHorizontal', hover) || 0,
        paddingVertical = pPaddingVertical || getRowStyle && getRowStyle('paddingVertical', hover) || 0,
        align = pAlign || getRowStyle && getRowStyle('textAlign', hover) || '',
        color = pColor || getRowStyle && getRowStyle('textColor', hover) || '',
        decoration = pDecoration || getRowStyle && getRowStyle('textDecoration', hover) || '',
        fontFamily = pFontFamily || getRowStyle && getRowStyle('fontFamily', hover) || '',
        fontSize = pFontSize || getRowStyle && getRowStyle('fontSize', hover) || 0,
        fontWeight = pFontWeight || getRowStyle && getRowStyle('textWeight', hover) || 0,
        fontStyle = pFontStyle || getRowStyle && getRowStyle('fontStyle', hover) || 0,
        iconSize = pIconSize || getRowStyle && getRowStyle('iconSize', hover) || 0,    
        iconWidth = iconSize ? (icon && (fontSize * 1.5) || 0) : 0,   
        positionY = rowsMeta.slice(0, ix).reduce((p, [,,{height}]) => p + height, 0),
        isRegistered = useRef(false),
        getBBox = useCallback(() => (bbox => ({
            height: bbox.height + 2 * paddingVertical,
            width: bbox.width + 2 * paddingHorizontal,
            x: bbox.x,
            y: bbox.y            
        }))($box.current.getBBox()), [paddingHorizontal, paddingVertical]),     
        textContent = isFoo(content) 
            ? content({
                width,
                color,
                fontSize,
                fontStyle,
                ix,
                paddingHorizontal: paddingHorizontal,
                paddingVertical: paddingVertical,
                borderColor: blockBorderColor,
                borderWidth: blockBorderWidth                
            }) 
            : content,// + '-' + ix + ':' + rowIX,
        txt = textContent.split('\n'),
        rAlign = align
        || (center && 'center')
        || (right && 'right')
        || 'left',
        getRegisterData = (name, relatable, relations) => [$box, 
            getBBox(),
            {relatable, relations, name, addRelation, removeRelation, onClick, onOver, onLeave}
        ];
    useEffect(() => {
        if(isRegistered.current) {
            updateRow(rowIX, getRegisterData(name, relatable, relations));
            // console.log(rowIX, relations, getRegisterData(name, relatable, relations))
        }
    }, [
        textContent, 
        fontSize, 
        fontWeight, 
        fontFamily,
        iconSize,
        (relations || []).join('-'),
        relatable,
        name
    ]);

    useEffect(() => {
        setIX(registerRow([
            rowIX, 
            ...getRegisterData(name, relatable, relations)
        ]));
        isRegistered.current = true;
        return () => {
            unregisterRow(rowIX);
        }
    }, [rowIX]);
    return (<g
        ref={$box}
        transform={`translate(0, ${(positionY || 0)})`}
    >
        {icon && <image
            y={paddingVertical + 0.5}
            x={0.5}
            xlinkHref={icon}
            width={iconSize}
            height={iconSize}
        />}   
        {txt.map((line, ix) => (<text
            key={ix}
            style={{
                dominantBaseline: 'hanging',
                textAnchor: rAlign === 'center'
                    ? 'middle'
                    : ( rAlign === 'right'
                        ? 'end'
                        : 'start'
                    )
            }}
            x={ rAlign === 'center'
                    ? ((ix === 0 && iconWidth || 0) + ((width - (ix === 0 && iconWidth || 0) - paddingHorizontal * 2)/2))
                    : ( rAlign === 'right'
                        ? (width - paddingHorizontal)
                        : ((ix === 0 && iconWidth || 0))
                    )
            }
            y={paddingVertical + (iconWidth ? iconWidth*.2 : 0) + (fontSize + paddingVertical) * ix}
            className={addClass(`${baseClass}-text`, className)}
            fontFamily={fontFamily || ''}
            fill={color || ''}
            fontSize={fontSize || 0}
            fontStyle={fontStyle || 'none'}
            textDecoration={decoration || 'none'}
            fontWeight={fontWeight || 'normal'}            
        >{line}</text>))}     
    </g>)
}