import { MarkerElem, MarkersConf, MarkerSerie } from '../models/marker';
import { LineTimeSerie, LineOptions } from '../types';

import { PodState } from '@chartwerk/core';

import d3 from 'd3';

export class Markers {
  private _layerContainer = null;
  private _chartHeight = 0;

  constructor(
    private _chartContainer: d3.Selection<HTMLElement, unknown, null, undefined>,
    private _markerConf: MarkersConf,
    private _state: PodState<LineTimeSerie, LineOptions>
  ) { }

  clear() {
    if(this._layerContainer !== null) {
      this._layerContainer.remove();
    }
    this._chartContainer.selectAll('.marker-content').remove();
  }

  render(metricContainer: d3.Selection<SVGGElement, unknown, null, undefined>, chartHeight: number) {
    this._chartHeight = chartHeight;
    this._layerContainer = metricContainer
      .append('g')
      .attr('class', 'markers-layer');
    for(const serie of this._markerConf.series) {
      this.renderSerie(serie);
    }
  }

  private _getLinePosition(marker: MarkerElem): number {
    return this._state.xScale(marker.x);
  }

  private _renderCircle(marker: MarkerElem) {
    const linePosition = this._getLinePosition(marker);

    let circle = this._layerContainer.append('circle')
      .attr('class', 'gap-circle')
      .attr('stroke', marker.color)
      .attr('stroke-width', '2px')
      .attr('r', 4)
      .attr('cx', linePosition)
      .attr('cy', 5)

    circle
      .attr('pointer-events', 'all')
      .style('cursor', 'pointer')
      .on('mousemove', () => {
        const onMouseMove = this._markerConf.events?.onMouseMove;
        if(onMouseMove) {
          onMouseMove(marker);
          return
        }
        if(marker.alwaysDisplay) {
          return;
        }
        this._chartContainer
          .selectAll(`.marker-content-${marker.x}`)
          .style('visibility', 'visible')
          .style('z-index', 9999);
      })
      .on('mouseout', () => {
        const onMouseOut = this._markerConf.events?.onMouseOut;
        if(onMouseOut) {
          onMouseOut()
          return
        }
        if(marker.alwaysDisplay) {
          return;
        }
        this._chartContainer
          .selectAll(`.marker-content-${marker.x}`)
          .style('visibility', 'hidden')
          .style('z-index', 1);
      });
  }

  private _renderLine(marker: MarkerElem) {
    const linePosition = this._getLinePosition(marker);

    this._layerContainer.append('line')
      .attr('class', 'gap-line')
      .attr('stroke', marker.color)
      .attr('stroke-width', '1px')
      .attr('stroke-opacity', '0.3')
      .attr('stroke-dasharray', '4')
      .attr('x1', linePosition)
      .attr('x2', linePosition)
      .attr('y1', 0)
      // @ts-ignore // TODO: remove ignore but boxParams are protected
      .attr('y2', this._state.boxParams.height)
      .attr('pointer-events', 'none');
  }

  private _renderTooltip(marker: MarkerElem) {
    if(marker.html === undefined) {
      return;
    }

    const linePosition = this._getLinePosition(marker);

    this._chartContainer
      .append('div')
      .attr('class', 'marker-content')
      .attr('class', `marker-content-${marker.x}`)
      // @ts-ignore // TODO: remove ignore but boxParams are protected
      .style('top', `${this._state.boxParams.height - this._chartHeight}px`)
      .style('left', `${linePosition + 50}px`)
      .style('visibility', marker.alwaysDisplay ? 'visible' : 'hidden')
      .style('position', 'absolute')
      .style('border', '1px solid black')
      .style('background-color', 'rgb(33, 37, 41)')
      .style('color', 'rgb(255, 255, 255)')
      .style('line-height', '1.55')
      .style('font-size', '0.875rem')
      .style('border-radius', '0.5rem')
      .style('padding', 'calc(0.3125rem) 0.625rem')
      .style('position', 'absolute')
      .style('white-space', 'nowrap')
      .style('pointer-events', 'none')
      .style('z-index', 1)
      .html(marker.html);
  }

  protected renderSerie(serie: MarkerSerie) {
    serie.data.forEach((marker: MarkerElem) => {
      this._renderLine(marker);
      this._renderCircle(marker);
      this._renderTooltip(marker);
    });
  }
}