import React, { memo, useCallback, HTMLAttributes, FC, useEffect, useState } from 'react';
import cc from 'classcat';

import { useStore } from '../../store';

import PlusIcon from '../../../assets/icons/plus.svg';
import MinusIcon from '../../../assets/icons/minus.svg';
import FitviewIcon from '../../../assets/icons/fitview.svg';
import LockIcon from '../../../assets/icons/lock.svg';
import UnlockIcon from '../../../assets/icons/unlock.svg';

import useZoomPanHelper from '../../hooks/useZoomPanHelper';
import { FitViewParams, ReactFlowState } from '../../types';

export interface ControlProps extends HTMLAttributes<HTMLDivElement> {
  showZoom?: boolean;
  showFitView?: boolean;
  showInteractive?: boolean;
  fitViewParams?: FitViewParams;
  onZoomIn?: () => void;
  onZoomOut?: () => void;
  onFitView?: () => void;
  onInteractiveChange?: (interactiveStatus: boolean) => void;
}

export interface ControlButtonProps extends HTMLAttributes<HTMLButtonElement> {}

export const ControlButton: FC<ControlButtonProps> = ({ children, className, ...rest }) => (
  <button className={cc(['react-flow__controls-button', className])} {...rest}>
    {children}
  </button>
);

const setInteractiveSelector = (s: ReactFlowState) => s.setInteractive;
const isInteractiveSelector = (s: ReactFlowState) => s.nodesDraggable && s.nodesConnectable && s.elementsSelectable;

const Controls: FC<ControlProps> = ({
  style,
  showZoom = true,
  showFitView = true,
  showInteractive = true,
  fitViewParams,
  onZoomIn,
  onZoomOut,
  onFitView,
  onInteractiveChange,
  className,
  children,
}) => {
  const [isVisible, setIsVisible] = useState<boolean>(false);
  const setInteractive = useStore(setInteractiveSelector);
  const isInteractive = useStore(isInteractiveSelector);
  const { zoomIn, zoomOut, fitView } = useZoomPanHelper();

  const mapClasses = cc(['react-flow__controls', className]);

  const onZoomInHandler = useCallback(() => {
    zoomIn?.();
    onZoomIn?.();
  }, [zoomIn, onZoomIn]);

  const onZoomOutHandler = useCallback(() => {
    zoomOut?.();
    onZoomOut?.();
  }, [zoomOut, onZoomOut]);

  const onFitViewHandler = useCallback(() => {
    fitView?.(fitViewParams);
    onFitView?.();
  }, [fitView, fitViewParams, onFitView]);

  const onInteractiveChangeHandler = useCallback(() => {
    setInteractive?.(!isInteractive);
    onInteractiveChange?.(!isInteractive);
  }, [isInteractive, setInteractive, onInteractiveChange]);

  useEffect(() => {
    setIsVisible(true);
  }, []);

  if (!isVisible) {
    return null;
  }

  return (
    <div className={mapClasses} style={style}>
      {showZoom && (
        <>
          <ControlButton onClick={onZoomInHandler} className="react-flow__controls-zoomin">
            <PlusIcon />
          </ControlButton>
          <ControlButton onClick={onZoomOutHandler} className="react-flow__controls-zoomout">
            <MinusIcon />
          </ControlButton>
        </>
      )}
      {showFitView && (
        <ControlButton className="react-flow__controls-fitview" onClick={onFitViewHandler}>
          <FitviewIcon />
        </ControlButton>
      )}
      {showInteractive && (
        <ControlButton className="react-flow__controls-interactive" onClick={onInteractiveChangeHandler}>
          {isInteractive ? <UnlockIcon /> : <LockIcon />}
        </ControlButton>
      )}
      {children}
    </div>
  );
};

Controls.displayName = 'Controls';

export default memo(Controls);
