import React, {useEffect, useRef, useState, forwardRef, useCallback} from 'react';
import addClass from 'reneco-utils/addClass';
import getOffsetRect from 'reneco-utils/getOffsetRect';
import './Scheme.scss';
// import SchemeBlock, {Row} from './Block';
import Blocks from './Blocks';
import SchemeBlock from './Block';
// import Links from './Links';
// import deltaPoints from './Utils/delta';
import {Provider as SchemeProvider} from './SchemeContext';
import Row from './Row';
import useDrag from './useDrag';
// import InlineFragment from './Inline';

const InlineFragment = () => {};


export default forwardRef(({
    zoomStep = 1.1,
    className,
    buttonZoomIn,
    buttonZoomOut,
    buttonFullScreen,
    onUnselect,
    children,
    // onMoveEnd,
    // onMove    

}, ref) => {
    const baseClass = 'reneco-components-scheme',
        $box = useRef(null),
        $svg = useRef(null),
        $scene = useRef(null),
        $blocks = useRef(null),
        [state, setState] = useState({
            width: 0,
            height: 0,
            zoom: 1,
            viewportX: 0,
            viewportY: 0,
            dragStarted: false,
        }),
        {
            width = 0,
            height = 0,
            zoom = 1,
            viewportX = 0,
            viewportY = 0,
            dragStarted
        } = state || {},
        /*
        x: nextScale / scale * (position.x - fixedPoint.x) + fixedPoint.x,
        y: nextScale / scale * (position.y - fixedPoint.y) + fixedPoint.y        
        
        */
        doZoom = useCallback((x, y, f) => (zoomMultifier => setState(({zoom, width, height, viewportX, viewportY, ...pState}) => (nZoom => {
                return ({
                    ...pState, 
                    width,
                    height,
                    viewportX: nZoom / zoom * (viewportX - x) + x,
                    viewportY: nZoom / zoom * (viewportY - y) + y,          
                    zoom: nZoom
                });
            })(zoom * zoomMultifier)))(f > 0 ? (1/zoomStep) : zoomStep), [zoomStep]),
        doZoomFullscreen = e => {
            e.stopPropagation();
            e.preventDefault();
            const schemaBBox = $scene.current.getBBox(),
                svgRatio = width / height,
                schemaRatio = schemaBBox.width / schemaBBox.height,
                z = (svgRatio < schemaRatio
                        ? (schemaBBox.height / (width / schemaRatio))
                        : (schemaBBox.width / (height * schemaRatio))
                ) * zoomStep;
            if(z !== zoom) {
                setState(pState => ({
                    ...pState, 
                    zoom: z,
                    viewportX: (schemaBBox.width - width*z) / 2,
                    viewportY: (schemaBBox.height - height*z) / 2                    
                }));
            }
        },        
        zoomIn = useCallback((x, y) => doZoom(x, y, 1), []),
        zoomOut = useCallback((x, y) => doZoom(x, y, -1), []),
        onWheel = useCallback(e => { 
            const boxPosition = getOffsetRect($box.current);
            if(e.deltaY < 0) {
                zoomIn(e.clientX-boxPosition.x, e.clientY-boxPosition.y);
                // zoomIn(e.clientX, e.clientY)
            } else if(e.deltaY > 0) {
                zoomOut(e.clientX-boxPosition.x, e.clientY-boxPosition.y);
                // zoomOut(e.clientX, e.clientY)
            }            
        }, []),
        onMouseUp = e => { console.log('onMouseUp', e)},
        onMouseDown = useCallback(e => $blocks.current.setSelected(null), []),
        // onBlockSelect = e => { console.log('onBlockSelect', e)},
        onResize = useCallback(() => ((boxHeight, boxWidth) => setState(({width, height, ...pState}) => (boxHeight !== height || boxWidth !== width)
            ? {...pState, width: boxWidth, height: boxHeight}
            : null
        ))($box.current.offsetHeight, $box.current.offsetWidth), []),
        onMove = useCallback(([x, y]) => setState(pState => ({...pState, viewportX: x, viewportY: y})), []),
        onMoveStart = useCallback(() => setState(pState => ({...pState, dragStarted: true})), []),
        onMoveEnd = useCallback(() => setState(pState => ({...pState, dragStarted: false})), []),
        [] = useDrag([viewportX, viewportY], 'scheme', {
            svg: $svg,
            zoom,
            reverse: true,
            onMove,
            onMoveEnd,
            onMoveStart,  
        }, $box);        
    useEffect(() => ((eResize, eMouseDown) => {
        window.addEventListener(eResize, onResize);
        $svg.current.addEventListener(eMouseDown, onMouseDown);
        onResize();
        if(ref) {
            ref.current = {fullScreen: doZoomFullscreen, zoomIn, zoomOut};
        }
        return () => {
            window.removeEventListener(eResize, onResize);
            $svg.current && $svg.current.removeEventListener(eMouseDown, onMouseDown);
            if(ref) { 
                ref.current = null;
            }
        }
    })('resize', 'mousedown'), []);
    return (<div
        ref={$box}
        className={addClass(baseClass, className)}    
    >
        <SchemeProvider value={{ 
            zoom,
            svg: $svg       
        }} >

            <svg
                ref={$svg}
                className={addClass(`${baseClass}-svg`, dragStarted && `${baseClass}-svg-drag-active`)}
                onWheel={onWheel}
                viewBox={`${Math.floor(viewportX)} ${Math.floor(viewportY)} ${width * zoom} ${height * zoom}`}
                onMouseLeave={onMouseUp}
                // onMouseUp={onMouseUp}
                style={{width, height}}
            >
                <g ref={$scene}>
                    <Blocks
                        ref={$blocks}
                        children={children}
                        onUnselect={onUnselect}
                    />                    
                </g>
            </svg>            
            <div className={`${baseClass}-buttons`}>
                {/* {buttonZoomIn && React.cloneElement(buttonZoomIn, {onClick: () => this.zoomIn()})}
                {buttonZoomOut && React.cloneElement(buttonZoomOut, {onClick: () => this.zoomOut()})}
                {buttonFullScreen && React.cloneElement(buttonFullScreen, {onClick: () => this.zoomFullscreen()})} */}
            </div>            
        </SchemeProvider>
    </div>)
});

export const Block = SchemeBlock;
export const BlockRow = Row;
export const RowFragment = InlineFragment;