import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { Tool } from '@psychobolt/react-paperjs';
import { Rectangle } from 'paper';
import flatten from 'lodash/flatten';
import { mapChildren } from './utils';
/** */
class EditTool extends Component {
  /** */
  constructor(props) {
    super(props);
    this.onMouseMove = this.onMouseMove.bind(this);
    this.onMouseDown = this.onMouseDown.bind(this);
    this.onMouseDrag = this.onMouseDrag.bind(this);
    this.onMouseUp = this.onMouseUp.bind(this);
  }

  /** */
  onMouseDown(e) {
    const { paper } = this.props;
    const { project } = paper;

    const paths = flatten(project.layers.map((layer) => (
      flatten(mapChildren(layer)).map((aPath) => aPath)
    )));

    paths.forEach((path) => {
      if (path.contains(e.point)) {
        path.data.state = 'moving'; // eslint-disable-line no-param-reassign
        return;
      }
      if (path.hitTest(e.point, { segments: true, tolerance: 15 })) {
        path.data.state = 'resizing'; // eslint-disable-line no-param-reassign
        path.data.bounds = path.bounds.clone(); // eslint-disable-line no-param-reassign
        path.data.scaleBase = e.point.subtract( // eslint-disable-line no-param-reassign
          path.bounds.center,
        );
      }
    });
  }

  /** */
  onMouseDrag(e) {
    const { paper } = this.props;
    const { project } = paper;

    const paths = flatten(project.layers.map((layer) => (
      flatten(mapChildren(layer)).map((aPath) => aPath)
    )));

    paths.forEach((path) => {
      if (path.data.state === 'moving') {
        // We need to do the JavaScript version rather than the PaperScript
        // https://github.com/paperjs/paper.js/issues/1486
        path.position = path.position.add( // eslint-disable-line no-param-reassign
          e.point.subtract(e.lastPoint),
        );
      } else if (path.data.state === 'resizing') {
        const { bounds } = path.data;
        const scale = e.point.subtract(bounds.center).length / path.data.scaleBase.length;
        const tlVec = bounds.topLeft.subtract(bounds.center).multiply(scale);
        const brVec = bounds.bottomRight.subtract(bounds.center).multiply(scale);
        const newBounds = new Rectangle(tlVec.add(bounds.center), brVec.add(bounds.center));
        path.bounds = newBounds; // eslint-disable-line no-param-reassign
      }
    });
  }

  /** */
  onMouseMove(e) {
    const { paper } = this.props;
    const { project } = paper;

    const paths = flatten(project.layers.map((layer) => (
      flatten(mapChildren(layer)).map((aPath) => aPath)
    )));

    project.activeLayer.selected = false;

    let anySelected = false;
    paths.forEach((path) => {
      if (path.contains(e.point) || path.hitTest(e.point, { segments: true, tolerance: 15 })) {
        const hitTest = path.hitTest(e.point, { segments: true, tolerance: 15 });
        let cursor = 'move';
        if (hitTest && hitTest.type === 'segment') {
          const difference = path.position.subtract(hitTest.segment.point);
          // Find the angle from the center of the path to the handle.
          const roundedAngle = Math.round(
            Math.atan(difference.y / difference.x) * 180 / Math.PI / 45,
          ) * 45;
          switch (true) {
            case (roundedAngle === 45):
              cursor = 'nwse-resize';
              break;
            case (roundedAngle === -45):
              cursor = 'nesw-resize';
              break;
            case (roundedAngle === 0):
              cursor = 'ew-resize';
              break;
            case (Math.abs(roundedAngle) === 90):
              cursor = 'ns-resize';
              break;
            default:
              return;
          }
        }
        paper.view.getElement().style.cursor = cursor;
        anySelected = true;
        path.selected = true; // eslint-disable-line no-param-reassign
      }
    });
    if (!anySelected) {
      paper.view.getElement().style.cursor = 'auto';
    }
  }

  /** */
  onMouseUp(e) {
    const { onPathAdd, paper } = this.props;
    const { project } = paper;

    const paths = flatten(project.layers.map((layer) => (
      flatten(mapChildren(layer)).map((aPath) => aPath)
    )));
    paths.forEach((path) => {
      path.data.state = null; // eslint-disable-line no-param-reassign
      onPathAdd(path);
    });
    paper.view.getElement().style.cursor = 'auto';
  }

  /** */
  render() {
    return (
      <Tool
        onMouseDown={this.onMouseDown}
        onMouseDrag={this.onMouseDrag}
        onMouseMove={this.onMouseMove}
        onMouseUp={this.onMouseUp}
      />
    );
  }
}

EditTool.propTypes = {
  onPathAdd: PropTypes.func.isRequired,
  paper: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
};

export default React.forwardRef((props, ref) => <EditTool innerRef={ref} {...props} />); // eslint-disable-line