"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.AutoCompleteInput = void 0;

var _preact = require("preact");

var _inputs = require("./inputs");

const resultEntryClasses = 'pa3';

const ResultItem = ({
  children,
  onClick,
  onFocus
}) => (0, _preact.h)("div", null, (0, _preact.h)("button", {
  "data-e2e": "resultButton",
  type: "button",
  onClick: onClick,
  onFocus: onFocus,
  className: "button-reset bg-transparent bn pa3 ma0 w-100 tl nowrap dark-blue"
}, children));

class AutoCompleteInput extends _preact.Component {
  constructor(props) {
    super(props);
    this.handleGlobalClick = this.handleGlobalClick.bind(this);
    this.clear = this.clear.bind(this);
    this.state = this.getStartingState();
    this.focusInput = this.focusInput.bind(this);

    this.handleInputFocus = () => this.setState({
      inputFocused: true
    });

    this.handleInputBlur = () => this.setState({
      inputFocused: false
    });

    this.keyDown = this.keyDown.bind(this);
    this.state.selectedId = props.item.value || '';
  }

  getInput() {
    return this.base && this.base.querySelector('input');
  }

  getStartingState() {
    const input = this.getInput();
    return {
      error: null,
      activeSearchTerm: '',
      matches: null,
      selectedId: '',
      focusedIndex: null,
      loading: false,
      searching: false,
      loadedObject: null,
      inputFocused: input && document.activeElement === input
    };
  }

  handleGlobalClick() {
    this.setState({
      activeSearchTerm: '',
      matches: null
    });
  }

  selectEntry(entry) {
    this.props.selectCallback(entry);
    this.setState(this.getStartingState());
  }

  selectNoMatch() {
    if (this.props.selectNoMatch) {
      this.props.selectNoMatch(this.state.activeSearchTerm);
      this.setState(this.getStartingState());
    }
  }

  componentDidMount() {
    window.addEventListener('click', this.handleGlobalClick);
    window.addEventListener('keydown', this.keyDown);
  }

  componentWillUnmount() {
    window.removeEventListener('click', this.handleGlobalClick);
    window.removeEventListener('keydown', this.keyDown);
  }

  componentDidUpdate(_, prevState) {
    if (!this.props.updateValue) {
      return;
    }

    const {
      activeSearchTerm,
      selectedId
    } = this.state;

    if (activeSearchTerm !== prevState.activeSearchTerm || selectedId !== prevState.selectedId) {
      if (selectedId) {
        this.props.updateValue(selectedId);
      } else {
        this.props.updateValue('');
      }
    }
  }

  keyDown(e) {
    const {
      inputFocused,
      focusedIndex,
      activeSearchTerm,
      matches
    } = this.state;

    if (!inputFocused && focusedIndex === null) {
      return;
    }

    const handler = {
      ArrowDown: e => {
        e.preventDefault();
        const nextFocusedIndex = focusedIndex === null ? 0 : focusedIndex + 1;
        const found = this.base.querySelectorAll('[data-e2e=resultButton]')[nextFocusedIndex];

        if (found) {
          found.focus();
          this.setState({
            focusedIndex: nextFocusedIndex
          });
        } else {
          this.setState({
            focusedIndex: null
          });
        }
      },
      ArrowUp: e => {
        e.preventDefault();

        if (focusedIndex === null) {
          return;
        }

        const nextFocusedIndex = focusedIndex === 0 ? null : focusedIndex - 1;

        if (nextFocusedIndex === null) {
          this.focusInput();
          return;
        }

        const found = this.base.querySelectorAll('[data-e2e=resultButton]')[nextFocusedIndex];

        if (found) {
          found.focus();
          this.setState({
            focusedIndex: nextFocusedIndex
          });
        } else {
          this.setState({
            focusedIndex: null
          });
        }
      },
      Enter: e => {
        if (inputFocused && activeSearchTerm) {
          e.preventDefault();

          if (matches) {
            if (matches.length) {
              this.selectEntry(matches[0]);
            } else {
              this.selectNoMatch();
            }
          }
        }
      }
    }[e.key];

    if (handler) {
      handler(e);
    }
  }

  focusInput() {
    const inputEl = this.base && this.base.querySelector('input');

    if (inputEl) {
      inputEl.focus();
    }

    this.setState({
      focusedIndex: null
    });
  }

  clear() {
    this.setState({
      loadedObject: null,
      selectedId: null
    }, this.focusInput);
  }

  render({
    item,
    doSearch,
    renderEntry,
    renderNoMatches
  }, {
    activeSearchTerm,
    matches,
    searching,
    focusedIndex
  }) {
    const noResults = matches && matches.length === 0;
    return (0, _preact.h)("div", {
      className: "relative"
    }, (0, _preact.h)(_inputs.Input, {
      className: item.inputClassName || 'w-50',
      placeholder: item.placeholder,
      value: activeSearchTerm,
      "data-e2e": "".concat(item.name, "Input"),
      onFocus: this.handleInputFocus,
      onBlur: this.handleInputBlur,
      onInput: e => {
        const searchString = e.target.value || '';
        const searching = !!searchString;
        this.setState({
          activeSearchTerm: searchString,
          matches: null,
          searching
        });

        if (!searching) {
          return;
        }

        doSearch(searchString).then(entry => {
          if (searchString === this.state.activeSearchTerm) {
            this.setState({
              matches: entry,
              searching: false,
              error: null
            });
          }
        }).catch(() => {
          if (searchString === this.state.activeSearchTerm) {
            this.setState({
              entry: null,
              error: true,
              searching: false
            });
          }
        });
      }
    }), (0, _preact.h)("div", null, (matches || searching) && (0, _preact.h)("div", {
      className: "absolute bg-white br2 ba b--gray z-1"
    }, (0, _preact.h)("div", {
      style: {
        maxHeight: 'calc(100vh - 90px)'
      },
      className: "overflow-scroll"
    }, matches && matches.length > 0 && matches.map((entry, index) => (0, _preact.h)(ResultItem, {
      onClick: () => this.selectEntry(entry),
      onFocus: () => this.setState({
        focusedIndex: index
      }),
      key: entry.id
    }, renderEntry(entry), ' ', (!focusedIndex && index === 0 || focusedIndex === index) && (0, _preact.h)("span", {
      className: "gray i"
    }, "push \"enter\" to select")))), noResults && renderNoMatches && (0, _preact.h)(ResultItem, {
      onClick: () => this.selectNoMatch()
    }, renderNoMatches(activeSearchTerm)), noResults && !renderNoMatches && (0, _preact.h)("div", {
      className: resultEntryClasses
    }, "No matches"), searching && (0, _preact.h)("div", {
      className: resultEntryClasses
    }, "Searching..."))));
  }

}

exports.AutoCompleteInput = AutoCompleteInput;