import React, { PureComponent } from "react";
import PropTypes from "prop-types";
import { defineMessages, injectIntl } from "react-intl";
import deviceInfo from "/imports/utils/deviceInfo";
import injectWbResizeEvent from "/imports/ui/components/presentation/resize-wrapper/component";
import {
  HUNDRED_PERCENT,
  MAX_PERCENT,
  STEP,
} from "/imports/utils/slideCalcUtils";
import Styled from "./styles";
import ZoomTool from "./zoom-tool/component";
import TooltipContainer from "/imports/ui/components/common/tooltip/container";
import KEY_CODES from "/imports/utils/keyCodes";

const intlMessages = defineMessages({
  previousSlideLabel: {
    id: "app.presentation.presentationToolbar.prevSlideLabel",
    description: "Previous slide button label",
  },
  previousSlideDesc: {
    id: "app.presentation.presentationToolbar.prevSlideDesc",
    description: "Aria description for when switching to previous slide",
  },
  nextSlideLabel: {
    id: "app.presentation.presentationToolbar.nextSlideLabel",
    description: "Next slide button label",
  },
  nextSlideDesc: {
    id: "app.presentation.presentationToolbar.nextSlideDesc",
    description: "Aria description for when switching to next slide",
  },
  noNextSlideDesc: {
    id: "app.presentation.presentationToolbar.noNextSlideDesc",
    description: "",
  },
  noPrevSlideDesc: {
    id: "app.presentation.presentationToolbar.noPrevSlideDesc",
    description: "",
  },
  skipSlideLabel: {
    id: "app.presentation.presentationToolbar.skipSlideLabel",
    description: "Aria label for when switching to a specific slide",
  },
  skipSlideDesc: {
    id: "app.presentation.presentationToolbar.skipSlideDesc",
    description: "Aria description for when switching to a specific slide",
  },
  goToSlide: {
    id: "app.presentation.presentationToolbar.goToSlide",
    description: "button for slide select",
  },
  selectLabel: {
    id: "app.presentation.presentationToolbar.selectLabel",
    description: "slide select label",
  },
  fitToWidth: {
    id: "app.presentation.presentationToolbar.fitToWidth",
    description: "button for fit to width",
  },
  fitToWidthDesc: {
    id: "app.presentation.presentationToolbar.fitWidthDesc",
    description: "Aria description to display the whole width of the slide",
  },
  fitToPage: {
    id: "app.presentation.presentationToolbar.fitToPage",
    description: "button label for fit to width",
  },
  fitToPageDesc: {
    id: "app.presentation.presentationToolbar.fitScreenDesc",
    description: "Aria description to display the whole slide",
  },
  presentationLabel: {
    id: "app.presentationUploder.title",
    description: "presentation area element label",
  },
});

class PresentationToolbar extends PureComponent {
  constructor(props) {
    super(props);

    this.state = {
      curPageId: 1,
    };

    this.handleSkipToSlideChange = this.handleSkipToSlideChange.bind(this);
    this.change = this.change.bind(this);
    this.renderAriaDescs = this.renderAriaDescs.bind(this);
    this.switchSlide = this.switchSlide.bind(this);
    this.nextSlideHandler = this.nextSlideHandler.bind(this);
    this.previousSlideHandler = this.previousSlideHandler.bind(this);
    this.fullscreenToggleHandler = this.fullscreenToggleHandler.bind(this);
  }

  componentDidMount() {
    document.addEventListener("keydown", this.switchSlide);
  }

  componentWillUnmount() {
    document.removeEventListener("keydown", this.switchSlide);
  }

  switchSlide(event) {
    const { target, which } = event;
    const isBody = target.nodeName === "BODY";

    if (isBody) {
      switch (which) {
        case KEY_CODES.ARROW_LEFT:
        case KEY_CODES.PAGE_UP:
          this.previousSlideHandler();
          break;
        case KEY_CODES.ARROW_RIGHT:
        case KEY_CODES.PAGE_DOWN:
          this.nextSlideHandler();
          break;
        case KEY_CODES.ENTER:
          this.fullscreenToggleHandler();
          break;
        default:
      }
    }
  }

  handleSkipToSlideChange(event) {
    const { skipToSlide, podId } = this.props;
    const requestedSlideNum = Number.parseInt(event.target.value, 10);

    if (event) event.currentTarget.blur();
    // skipToSlide(requestedSlideNum, podId);
    this.props?.tldrawAPI?.changePage(requestedSlideNum);
    this.setState({
      curPageId: parseInt(this.props?.tldrawAPI?.getPage()?.id),
    });
  }

  nextSlideHandler(event) {
    const { nextSlide, currentSlideNum, numberOfSlides, podId } = this.props;

    if (event) event.currentTarget.blur();
    nextSlide(currentSlideNum, numberOfSlides, podId);
  }

  previousSlideHandler(event) {
    const { previousSlide, currentSlideNum, podId } = this.props;

    if (event) event.currentTarget.blur();
    previousSlide(currentSlideNum, podId);
  }

  fullscreenToggleHandler() {
    const {
      fullscreenElementId,
      isFullscreen,
      layoutContextDispatch,
      fullscreenAction,
      fullscreenRef,
      handleToggleFullScreen,
    } = this.props;

    handleToggleFullScreen(fullscreenRef);
    const newElement = isFullscreen ? "" : fullscreenElementId;

    layoutContextDispatch({
      type: fullscreenAction,
      value: {
        element: newElement,
        group: "",
      },
    });
  }

  change(value) {
    const { zoomChanger } = this.props;
    zoomChanger(value);
  }

  renderAriaDescs() {
    const { intl } = this.props;
    return (
      <div hidden>
        {/* Aria description's for toolbar buttons */}
        <div id="prevSlideDesc">
          {intl.formatMessage(intlMessages.previousSlideDesc)}
        </div>
        <div id="noPrevSlideDesc">
          {intl.formatMessage(intlMessages.noPrevSlideDesc)}
        </div>
        <div id="nextSlideDesc">
          {intl.formatMessage(intlMessages.nextSlideDesc)}
        </div>
        <div id="noNextSlideDesc">
          {intl.formatMessage(intlMessages.noNextSlideDesc)}
        </div>
        <div id="skipSlideDesc">
          {intl.formatMessage(intlMessages.skipSlideDesc)}
        </div>
        <div id="fitWidthDesc">
          {intl.formatMessage(intlMessages.fitToWidthDesc)}
        </div>
        <div id="fitPageDesc">
          {intl.formatMessage(intlMessages.fitToPageDesc)}
        </div>
      </div>
    );
  }

  renderSkipSlideOpts(numberOfSlides) {
    // Fill drop down menu with all the slides in presentation
    const { intl } = this.props;
    const optionList = [];
    for (let i = 1; i <= numberOfSlides; i += 1) {
      optionList.push(
        <option value={i} key={i}>
          {intl.formatMessage(intlMessages.goToSlide, { 0: i })}
        </option>
      );
    }

    return optionList;
  }

  render() {
    const {
      currentSlideNum,
      numberOfSlides,
      fitToWidthHandler,
      fitToWidth,
      intl,
      zoom,
      isMeteorConnected,
      isPollingEnabled,
      amIPresenter,
      currentSlidHasContent,
      parseCurrentSlideContent,
      startPoll,
      currentSlide,
      toolbarWidth,
    } = this.props;

    const { isMobile } = deviceInfo;

    const startOfSlides = parseInt(this.state.curPageId) === 1;
    const endOfSlides = parseInt(this.state.curPageId) === numberOfSlides;

    const prevSlideAriaLabel = startOfSlides
      ? intl.formatMessage(intlMessages.previousSlideLabel)
      : `${intl.formatMessage(intlMessages.previousSlideLabel)} (${
          parseInt(this.props?.tldrawAPI?.getPage()?.id) <= 1
            ? ""
            : parseInt(this.props?.tldrawAPI?.getPage()?.id) - 1
        })`;

    const nextSlideAriaLabel = endOfSlides
      ? intl.formatMessage(intlMessages.nextSlideLabel)
      : `${intl.formatMessage(intlMessages.nextSlideLabel)} (${
          parseInt(this.props?.tldrawAPI?.getPage()?.id) >= 1
            ? parseInt(this.props?.tldrawAPI?.getPage()?.id) + 1
            : ""
        })`;

    return (
      <Styled.PresentationToolbarWrapper
        id="presentationToolbarWrapper"
        style={{
          width: "100%",
        }}
      >
        {this.renderAriaDescs()}
        {
          <div>
            {isPollingEnabled ? (
              <Styled.QuickPollButton
                {...{
                  currentSlidHasContent,
                  intl,
                  amIPresenter,
                  parseCurrentSlideContent,
                  startPoll,
                  currentSlide,
                }}
              />
            ) : null}
          </div>
        }
        {
          <Styled.PresentationSlideControls>
            <Styled.PrevSlideButton
              role="button"
              aria-label={prevSlideAriaLabel}
              aria-describedby={
                startOfSlides ? "noPrevSlideDesc" : "prevSlideDesc"
              }
              disabled={startOfSlides || !isMeteorConnected}
              color="default"
              icon="left_arrow"
              size="md"
              onClick={() => {
                this.props?.tldrawAPI?.changePage(
                  parseInt(this.props?.tldrawAPI?.getPage()?.id) - 1
                );
                this.setState({
                  curPageId: parseInt(this.props?.tldrawAPI?.getPage()?.id),
                });
              }}
              label={intl.formatMessage(intlMessages.previousSlideLabel)}
              hideLabel
              data-test="prevSlide"
            />

            <TooltipContainer
              title={intl.formatMessage(intlMessages.selectLabel)}
            >
              <Styled.SkipSlideSelect
                id="skipSlide"
                aria-label={intl.formatMessage(intlMessages.skipSlideLabel)}
                aria-describedby="skipSlideDesc"
                aria-live="polite"
                aria-relevant="all"
                disabled={!isMeteorConnected}
                value={this.state.curPageId}
                onChange={this.handleSkipToSlideChange}
                data-test="skipSlide"
              >
                {this.renderSkipSlideOpts(numberOfSlides)}
              </Styled.SkipSlideSelect>
            </TooltipContainer>
            <Styled.NextSlideButton
              role="button"
              aria-label={nextSlideAriaLabel}
              aria-describedby={
                endOfSlides ? "noNextSlideDesc" : "nextSlideDesc"
              }
              disabled={endOfSlides || !isMeteorConnected}
              color="default"
              icon="right_arrow"
              size="md"
              onClick={() => {
                this.props?.tldrawAPI?.changePage(
                  parseInt(this.props?.tldrawAPI?.getPage()?.id) + 1
                );
                this.setState({
                  curPageId: parseInt(this.props?.tldrawAPI?.getPage()?.id),
                });
              }}
              label={intl.formatMessage(intlMessages.nextSlideLabel)}
              hideLabel
              data-test="nextSlide"
            />
          </Styled.PresentationSlideControls>
        }
        {
          <Styled.PresentationZoomControls>
            {!isMobile ? (
              <TooltipContainer>
                <ZoomTool
                  zoomValue={
                    this.props?.tldrawAPI?.getPageState()?.camera?.zoom
                  }
                  change={this.change}
                  minBound={0.1}
                  maxBound={5}
                  step={STEP}
                  isMeteorConnected={isMeteorConnected}
                  tldrawAPI={this.props?.tldrawAPI}
                />
              </TooltipContainer>
            ) : null}
            <Styled.FitToWidthButton
              role="button"
              aria-describedby={fitToWidth ? "fitPageDesc" : "fitWidthDesc"}
              aria-label={
                fitToWidth
                  ? `${intl.formatMessage(
                      intlMessages.presentationLabel
                    )} ${intl.formatMessage(intlMessages.fitToPage)}`
                  : `${intl.formatMessage(
                      intlMessages.presentationLabel
                    )} ${intl.formatMessage(intlMessages.fitToWidth)}`
              }
              color="default"
              disabled={!isMeteorConnected}
              icon="fit_to_width"
              size="md"
              circle={false}
              onClick={() => this.props.tldrawAPI.zoomToFit()}
              label={intl.formatMessage(intlMessages.fitToPage)}
              hideLabel
            />
          </Styled.PresentationZoomControls>
        }
      </Styled.PresentationToolbarWrapper>
    );
  }
}

PresentationToolbar.propTypes = {
  // The Id for the current pod. Should always be default pod
  podId: PropTypes.string.isRequired,
  // Number of current slide being displayed
  currentSlideNum: PropTypes.number.isRequired,
  // Total number of slides in this presentation
  numberOfSlides: PropTypes.number.isRequired,
  // Actions required for the presenter toolbar
  nextSlide: PropTypes.func.isRequired,
  previousSlide: PropTypes.func.isRequired,
  skipToSlide: PropTypes.func.isRequired,
  intl: PropTypes.shape({
    formatMessage: PropTypes.func.isRequired,
  }).isRequired,
  zoomChanger: PropTypes.func.isRequired,
  fitToWidthHandler: PropTypes.func.isRequired,
  fitToWidth: PropTypes.bool.isRequired,
  zoom: PropTypes.number.isRequired,
  isMeteorConnected: PropTypes.bool.isRequired,
  fullscreenElementId: PropTypes.string.isRequired,
  fullscreenAction: PropTypes.string.isRequired,
  isFullscreen: PropTypes.bool.isRequired,
  layoutContextDispatch: PropTypes.func.isRequired,
};

export default injectWbResizeEvent(injectIntl(PresentationToolbar));
