import React, { Component } from "react";
import PropTypes from "prop-types";
import classnames from "classnames";
import { isEqual, noop } from "lodash";

import targetsAPI from "services/entities/targets";
import targetInterface from "interfaces/target";
import { formatSelectedTargetsForApi } from "utilities/helpers";

import Button from "components/buttons/Button";
import Icon from "components/Icon";
import Input from "./SelectTargetsInput";
import Menu from "./SelectTargetsMenu";

const baseClass = "target-select";

class SelectTargetsDropdown extends Component {
  static propTypes = {
    disabled: PropTypes.bool,
    error: PropTypes.string,
    label: PropTypes.string,
    onFetchTargets: PropTypes.func,
    onSelect: PropTypes.func.isRequired,
    selectedTargets: PropTypes.arrayOf(targetInterface),
    targetsCount: PropTypes.number,
    queryId: PropTypes.number,
    isPremiumTier: PropTypes.bool,
  };

  static defaultProps = {
    disabled: false,
    onFetchTargets: noop,
  };

  constructor(props) {
    super(props);

    this.state = {
      isEmpty: false,
      isLoadingTargets: false,
      moreInfoTarget: null,
      query: "",
      targets: [],
    };
  }

  componentWillMount() {
    this.mounted = true;
    this.wrapperHeight = 0;
    this.fetchTargets();
    return false;
  }

  componentWillReceiveProps(nextProps) {
    const { selectedTargets } = nextProps;
    const { query } = this.state;
    const { queryId } = this.props;

    if (!isEqual(selectedTargets, this.props.selectedTargets)) {
      this.fetchTargets(query, queryId, selectedTargets);
    }
  }

  componentWillUnmount() {
    this.mounted = false;
  }

  onInputClose = () => {
    const { document } = global;
    const coreWrapper = document.querySelector(".core-wrapper");

    this.setState({ moreInfoTarget: null, query: "" });
    coreWrapper.style.height = "auto";

    return false;
  };

  onInputFocus = () => {
    const { document } = global;
    this.wrapperHeight = document.querySelector(".core-wrapper").scrollHeight;

    return false;
  };

  onInputOpen = () => {
    const { document } = global;
    const { wrapperHeight } = this;

    const lookForOuterMenu = setInterval(() => {
      if (document.querySelectorAll(".Select-menu-outer")) {
        clearInterval(lookForOuterMenu);
        const coreWrapper = document.querySelector(".core-wrapper");

        const currentWrapperHeight = coreWrapper.scrollHeight;
        if (wrapperHeight < currentWrapperHeight) {
          coreWrapper.style.height = `${
            wrapperHeight + (currentWrapperHeight - wrapperHeight) + 15
          }px`;
        }
      }
    }, 5);

    return false;
  };

  onTargetSelectMoreInfo = (moreInfoTarget) => {
    return (evt) => {
      evt.preventDefault();

      const currentMoreInfoTarget = this.state.moreInfoTarget || {};

      if (isEqual(moreInfoTarget.id, currentMoreInfoTarget.id)) {
        return false;
      }

      this.setState({ moreInfoTarget });

      return false;
    };
  };

  onBackToResults = () => {
    this.setState({ moreInfoTarget: null });
  };

  fetchTargets = (
    query = "",
    queryId = this.props.queryId,
    selectedTargets = this.props.selectedTargets
  ) => {
    const { onFetchTargets } = this.props;

    if (!this.mounted) {
      return false;
    }

    this.setState({ isLoadingTargets: true, query });

    return targetsAPI
      .DEPRECATED_loadAll(
        query,
        queryId,
        formatSelectedTargetsForApi(selectedTargets)
      )
      .then((response) => {
        const { targets } = response;
        const isEmpty = targets.length === 0;

        if (!this.mounted) {
          return false;
        }

        if (isEmpty) {
          // We don't want the lib's default "No Results" so we fake it
          targets.push({});
        }

        onFetchTargets(query, response);

        this.setState({
          isEmpty,
          isLoadingTargets: false,
          targets,
        });

        return query;
      })
      .catch((error) => {
        console.error("Error getting targets:", error);

        if (this.mounted) {
          this.setState({ isLoadingTargets: false });
        }
      });
  };

  renderLabel = () => {
    const { error, label, targetsCount } = this.props;

    const labelClassName = classnames(`${baseClass}__label`, {
      [`${baseClass}__label--error`]: error,
    });

    if (!label) {
      return false;
    }

    return (
      <p className={labelClassName}>
        <span className={`${baseClass}__select-targets`}>{error || label}</span>
        <span className={`${baseClass}__targets-count`}>
          {" "}
          {targetsCount} unique {targetsCount === 1 ? "host" : "hosts"}
        </span>
      </p>
    );
  };

  render() {
    const { isEmpty, isLoadingTargets, moreInfoTarget, targets } = this.state;
    const {
      fetchTargets,
      onBackToResults,
      onInputClose,
      onInputOpen,
      onInputFocus,
      onTargetSelectMoreInfo,
      renderLabel,
    } = this;
    const { disabled, onSelect, selectedTargets, isPremiumTier } = this.props;

    const menuRenderer = Menu(
      onTargetSelectMoreInfo,
      moreInfoTarget,
      onBackToResults,
      isPremiumTier
    );

    const inputClasses = classnames({
      "show-preview": moreInfoTarget,
      "is-empty": isEmpty,
    });

    const ArrowRenderer = ({ isOpen }) => (
      <div
        className={classnames("target-select__arrow", {
          "target-select__arrow--open": isOpen,
        })}
      >
        <Icon name="chevron-down" />
      </div>
    );

    const ClearRenderer = () => (
      <Button
        type="button"
        className="target-select__clear"
        onMouseDown={(e) => e.preventDefault()}
        variant="inverse"
      >
        <Icon name="close" />
      </Button>
    );

    return (
      <div className={`${baseClass}__wrapper form-field`}>
        {renderLabel()}
        <Input
          className={inputClasses}
          disabled={disabled}
          isLoading={isLoadingTargets}
          menuRenderer={menuRenderer}
          onClose={onInputClose}
          onOpen={onInputOpen}
          onFocus={onInputFocus}
          onTargetSelect={onSelect}
          onTargetSelectInputChange={fetchTargets}
          selectedTargets={selectedTargets}
          targets={targets}
          isPremiumTier={isPremiumTier}
          arrowRenderer={ArrowRenderer}
          clearRenderer={ClearRenderer}
        />
      </div>
    );
  }
}

export default SelectTargetsDropdown;
