import appState from  './state'
import convertToElement from './convertToElement'
import { renderScene } from './renderer/renderScene'
import { getElementsAtPosition, hitTest } from './element/collision'
import { setCursor } from './utils'
import { CURSOR_TYPE } from './constants'

export default class AnnotationManager {
  constructor (options) {
    this.container = options.container || null
    this.annotations = options.annotations || []
    this.appState = appState
    this.viewport = options.viewport
    this.onPointerMove = this.handleCanvasPointerMove.bind(this)

    this.initializeScene()
  }

  changeState (state) {
    this.appState = {
      ...this.appState,
      ...state
    }
  }

  initializeScene () {
    if (!this.canvas) {
      const canvasScale = window.devicePixelRatio;

      const container = this.container
      const { width, height } = container.getBoundingClientRect()
      const canvasDomWidth = width
      const canvasDomHeight = height
      const canvasWidth = canvasDomWidth * canvasScale
      const canvasHeight = canvasDomHeight * canvasScale
      const canvas = document.createElement('canvas')
      canvas.setAttribute('width', canvasWidth)
      canvas.setAttribute('height', canvasHeight)
      canvas.style.width = canvasDomWidth + 'px'
      canvas.style.height = canvasDomHeight + 'px'
      canvas.style.position = 'absolute'
      canvas.style.zIndex = 33
      this.canvas = canvas
      this.ctx = canvas.getContext('2d')
      if (this.container) {
        this.container.append(canvas)
      }
      this.canvas.addEventListener('pointermove', this.onPointerMove)
      if (this.annotations.length) {
        this.elements = convertToElement(this.annotations, this.viewport)
        this.render()
      }
    }
  }

  render () {
    renderScene({
      elements: this.elements,
      canvas: this.canvas,
      renderConfig: {
        viewport: this.viewport
      }
    })
  }

  viewportCoordsToSceneCoords ({ clientX, clientY }) {
    const { left, top } = this.container.getBoundingClientRect()
    const x = clientX - left - window.scrollX;
    const y = clientY - top - window.scrollY;

    return { x, y };
  }

  handleCanvasPointerMove = (event) => {
    this.appState.clientX = event.clientX
    this.appState.clientX = event.clientX

    const scenePointer = this.viewportCoordsToSceneCoords(event);

    const hitElement = this.getElementAtPosition(
      scenePointer.x,
      scenePointer.y,
    );
    if (hitElement) {
      setCursor(this.canvas, CURSOR_TYPE.POINTER);
    } else {
      setCursor(this.canvas, CURSOR_TYPE.AUTO);
    }
  }

  getElementAtPosition(
    x,
    y,
  ) {
    const allHitElements = this.getElementsAtPosition(
      x,
      y,
    );
    if (allHitElements.length === 1) {
      return allHitElements[0];
    }
    return null;
  }

  getElementsAtPosition(
    x,
    y,
  ) {
    const elements =
      this.elements.filter(
        (element) => !element.isDelete
      );

    return getElementsAtPosition(elements, (element) =>
      hitTest(element, this.appState, x, y),
    );
  }
}
