import React from "react";
import { isHtmlElement } from "../../util/dom";

const SCREEN_PADDING = 16;

export interface Props {
  screenLeft: number;
  screenTop: number;
}

export class CenteredAtPoint extends React.Component<Props> {
  private offsetParent: HTMLElement | undefined | null;
  private span: HTMLSpanElement | undefined | null;

  public componentWillUpdate() {
    this.span!.style.marginLeft = null;
  }

  public componentDidUpdate() {
    this.updatePositionStyle();
  }

  public render() {
    return (
      <span
        ref={this.handleRef}
        style={{
          position: "absolute",
          zIndex: 20,
          transform: "translate(-50%, 1em)"
        }}
      >
        {this.props.children}
      </span>
    );
  }

  private updatePositionStyle() {
    if (this.offsetParent != null && this.span != null && typeof window !== "undefined") {
      this.span.style.top = `${window.scrollY + this.props.screenTop - this.offsetParent.offsetTop}px`;
      this.span.style.left = `${window.scrollX + this.props.screenLeft - this.offsetParent.offsetLeft}px`;
      const boundingClientRect = this.span.getBoundingClientRect();
      if (boundingClientRect.left < SCREEN_PADDING) {
        this.span.style.marginLeft = `${0 - boundingClientRect.left + SCREEN_PADDING}px`;
      }
    }
  }

  private readonly handleRef = (span: HTMLSpanElement | null) => {
    this.span = span;
    if (span !== null) {
      this.offsetParent = this.findOffsetParent(span);
      this.updatePositionStyle();
    } else {
      this.offsetParent = null;
    }
  };

  private findOffsetParent(domNode: Element | null): HTMLElement | null {
    if (domNode !== null && isHtmlElement(domNode)) {
      const { offsetParent } = domNode;
      if (isHtmlElement(offsetParent)) {
        return offsetParent;
      }
    }
    return null;
  }
}
