// @ts-nocheck
import clsx from 'clsx';
import PropTypes from 'prop-types';
import React from 'react';

import AddTrackPositionMenu from './AddTrackPositionMenu';
import ConfigViewMenu from './ConfigViewMenu';
import ContextMenuContainer from './ContextMenuContainer';
import PopupMenu from './PopupMenu';

// HOCS
import withTheme from './hocs/with-theme';

// Configs
import {
  MOUSE_TOOL_SELECT,
  THEME_DARK,
  VIEW_HEADER_MED_WIDTH_SEARCH_BAR,
  VIEW_HEADER_MIN_WIDTH_SEARCH_BAR,
} from './configs';

// Styles
import classes from '../styles/ViewHeader.module.scss';

class ViewHeader extends React.Component {
  constructor(props) {
    super(props);

    this.configImg = null;
    this.plusImg = null;

    this.state = {
      addTrackPositionMenuUid: null,
      addTrackPositionMenuPosition: null,
      configMenuUid: null,
      configMenuPosition: null,
      isFocused: false,
      width: -1,
    };

    this.handleTrackPositionChosenBound =
      this.handleTrackPositionChosen.bind(this);
  }

  componentDidMount() {
    this.setState({ width: this.el.clientWidth });
  }

  checkWidth() {
    const width = this.el.clientWidth;

    if (width !== this.state.width) this.setState({ width });
  }

  /**
   * The user clicked on the `cog` of the menu so we need to open
   * it.
   */
  handleConfigMenuOpened(uid) {
    this.setState({
      configMenuUid: uid,
      configMenuPosition: this.configImg.getBoundingClientRect(),
    });
  }

  /**
   * The user has clicked on the 'plus' sign at the top of a TiledPlot
   * so we need to open the Track Position Chooser dialog
   */
  handleAddTrackPositionMenuOpened(uid) {
    this.setState({
      addTrackPositionMenuUid: uid,
      addTrackPositionMenuPosition: this.plusImg.getBoundingClientRect(),
    });
  }

  /**
   * The user has chosen a position for the new track. The actual
   * track selection will be handled by TiledPlot
   *
   * We just need to close the menu here.
   */
  handleTrackPositionChosen(position, extent) {
    this.props.onTrackPositionChosen(position, extent);

    this.setState({
      addTrackPositionMenuUid: null,
      addTrackPositionMenuPosition: null,
    });
  }

  render() {
    let configMenu = null;
    let addTrackPositionMenu = null;

    if (this.state.addTrackPositionMenuPosition) {
      addTrackPositionMenu = (
        <PopupMenu
          onMenuClosed={() => {
            this.setState({
              addTrackPositionMenuUid: null,
              addTrackPositionMenuPosition: null,
            });
          }}
        >
          <ContextMenuContainer
            orientation="left"
            position={this.state.addTrackPositionMenuPosition}
            theme={this.props.theme}
          >
            <AddTrackPositionMenu
              onTrackPositionChosen={this.handleTrackPositionChosenBound}
            />
          </ContextMenuContainer>
        </PopupMenu>
      );
    }

    if (this.state.configMenuUid) {
      configMenu = (
        <PopupMenu onMenuClosed={() => this.setState({ configMenuUid: null })}>
          <ConfigViewMenu
            onClearView={() => {
              this.setState({ configMenuUid: null }); // hide the menu
              this.props.onClearView();
            }}
            onEditViewConfig={() => {
              this.setState({ configMenuUid: null }); // hide the menu
              this.props.onEditViewConfig(this.state.configMenuUid);
            }}
            onExportPNG={() => {
              this.setState({ configMenuUid: null }); // hide the menu
              this.props.onExportPNG();
            }}
            onExportSVG={() => {
              this.setState({ configMenuUid: null }); // hide the menu
              this.props.onExportSVG();
            }}
            onExportViewAsJSON={() => {
              this.setState({ configMenuUid: null }); // hide the menu
              this.props.onExportViewsAsJSON();
            }}
            onExportViewAsLink={() => {
              this.setState({ configMenuUid: null }); // hide the menu
              this.props.onExportViewsAsLink();
            }}
            onLockLocation={() => {
              this.setState({ configMenuUid: null }); // hide the menu
              this.props.onLockLocation(this.state.configMenuUid);
            }}
            onLockZoom={() => {
              this.setState({ configMenuUid: null }); // hide the menu
              this.props.onLockZoom(this.state.configMenuUid);
            }}
            onLockZoomAndLocation={() => {
              this.setState({ configMenuUid: null }); // hide the menu
              this.props.onLockZoomAndLocation(this.state.configMenuUid);
            }}
            onOptionsChanged={(newOptions) => {
              this.props.onViewOptionsChanged(newOptions);
              this.setState({ configMenuUid: null }); // hide the menu
            }}
            onProjectViewport={() => {
              this.setState({ configMenuUid: null }); // hide the menu
              this.props.onProjectViewport(this.state.configMenuUid);
            }}
            onTakeAndLockZoomAndLocation={() => {
              this.setState({ configMenuUid: null }); // hide the menu
              this.props.onTakeAndLockZoomAndLocation(this.state.configMenuUid);
            }}
            onTogglePositionSearchBox={() => {
              this.setState({ configMenuUid: null }); // hide the menu
              this.props.onTogglePositionSearchBox(this.state.configMenuUid);
            }}
            onUnlockLocation={() => {
              this.setState({ configMenuUid: null }); // hide the menu
              this.props.onUnlockLocation(this.state.configMenuUid);
            }}
            onUnlockZoom={() => {
              this.setState({ configMenuUid: null }); // hide the menu
              this.props.onUnlockZoom(this.state.configMenuUid);
            }}
            onUnlockZoomAndLocation={() => {
              this.setState({ configMenuUid: null }); // hide the menu
              this.props.onUnlockZoomAndLocation(this.state.configMenuUid);
            }}
            onYankLocation={() => {
              this.setState({ configMenuUid: null }); // hide the menu
              this.props.onYankLocation(this.state.configMenuUid);
            }}
            onYankZoom={() => {
              this.setState({ configMenuUid: null }); // hide the menu
              this.props.onYankZoom(this.state.configMenuUid);
            }}
            onYankZoomAndLocation={() => {
              this.setState({ configMenuUid: null }); // hide the menu
              this.props.onYankZoomAndLocation(this.state.configMenuUid);
            }}
            onZoomToData={() => {
              this.setState({ configMenuUid: null }); // hide the menu
              this.props.onZoomToData(this.state.configMenuUid);
            }}
            orientation="left"
            position={this.state.configMenuPosition}
            theme={this.props.theme}
          />
        </PopupMenu>
      );
    }

    const GenomePositionSearchBox = this.props.getGenomePositionSearchBox(
      this.state.isFocused,
      (focus) => {
        this.setState({
          isFocused: focus,
        });
      },
    );

    const className = clsx(
      this.state.isFocused
        ? classes['multitrack-header-focus']
        : classes['multitrack-header'],
      {
        [classes['multitrack-header-dark']]: this.props.theme === THEME_DARK,
      },
    );

    const classNameIcon =
      this.state.width <= VIEW_HEADER_MED_WIDTH_SEARCH_BAR
        ? classes['multitrack-header-icon-squeazed']
        : classes['multitrack-header-icon'];

    return (
      <div
        ref={(c) => {
          this.el = c;
        }}
        className={className}
      >
        <div className={classes['multitrack-header-left']}>
          {this.props.mouseTool === MOUSE_TOOL_SELECT && (
            <svg
              className={clsx(classes['mouse-tool-selection'], classNameIcon)}
            >
              <title>Selection tool active</title>
              <use xlinkHref="#select" />
            </svg>
          )}
          <div
            className={classes['multitrack-header-grabber']}
            title="Drag to move the view"
          >
            <div />
            <div />
            <div />
          </div>
          {this.state.width > VIEW_HEADER_MIN_WIDTH_SEARCH_BAR && (
            <div className={classes['multitrack-header-search']}>
              {this.props.isGenomePositionSearchBoxVisible &&
                GenomePositionSearchBox}
            </div>
          )}
        </div>
        <nav className={classes['multitrack-header-nav-list']}>
          <svg className={classNameIcon} onClick={this.props.onAddView}>
            <title>Add new view (clone this view)</title>
            <use xlinkHref="#copy" />
          </svg>

          <svg
            ref={(c) => {
              this.configImg = c;
            }}
            className={classNameIcon}
            onClick={() => this.handleConfigMenuOpened(this.props.viewUid)}
          >
            <title>Configure this view</title>
            <use xlinkHref="#cog" />
          </svg>

          <svg
            ref={(c) => {
              this.plusImg = c;
            }}
            className={classNameIcon}
            onClick={() =>
              this.handleAddTrackPositionMenuOpened(this.props.viewUid)
            }
            data-testid="add-track"
          >
            <title>Add Track</title>
            <use xlinkHref="#plus" />
          </svg>

          <svg className={classNameIcon} onClick={this.props.onCloseView}>
            <title>Close View</title>
            <use xlinkHref="#cross" />
          </svg>
        </nav>

        {configMenu}
        {addTrackPositionMenu}
      </div>
    );
  }
}

ViewHeader.defaultProps = {
  isGenomePositionSearchBoxVisible: false,
};

ViewHeader.propTypes = {
  getGenomePositionSearchBox: PropTypes.func.isRequired,
  isGenomePositionSearchBoxVisible: PropTypes.bool,
  mouseTool: PropTypes.string.isRequired,
  onAddView: PropTypes.func.isRequired,
  onClearView: PropTypes.func.isRequired,
  onCloseView: PropTypes.func.isRequired,
  onEditViewConfig: PropTypes.func.isRequired,
  onExportSVG: PropTypes.func.isRequired,
  onExportPNG: PropTypes.func.isRequired,
  onExportViewsAsJSON: PropTypes.func.isRequired,
  onExportViewsAsLink: PropTypes.func.isRequired,
  onLockLocation: PropTypes.func.isRequired,
  onLockZoom: PropTypes.func.isRequired,
  onLockZoomAndLocation: PropTypes.func.isRequired,
  onProjectViewport: PropTypes.func.isRequired,
  onTakeAndLockZoomAndLocation: PropTypes.func.isRequired,
  onTogglePositionSearchBox: PropTypes.func.isRequired,
  onTrackPositionChosen: PropTypes.func.isRequired,
  onUnlockLocation: PropTypes.func.isRequired,
  onUnlockZoom: PropTypes.func.isRequired,
  onUnlockZoomAndLocation: PropTypes.func.isRequired,
  onViewOptionsChanged: PropTypes.func.isRequired,
  onYankLocation: PropTypes.func.isRequired,
  onYankZoom: PropTypes.func.isRequired,
  onYankZoomAndLocation: PropTypes.func.isRequired,
  onZoomToData: PropTypes.func.isRequired,
  theme: PropTypes.symbol.isRequired,
  viewUid: PropTypes.string.isRequired,
};

export default withTheme(ViewHeader);
