/**
 * Copyright 2019 Google Inc. All Rights Reserved.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *     http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import { h, Component } from 'preact';
import * as comlink from 'comlink';

import Transition from '../transition';
import { animate } from 'client/utils';

interface IframeComlink {
  [comlink.releaseProxy]: () => void;
  [prop: string]: () => Promise<void>;
}

interface Props {
  src: string;
  actionTarget: import('./').IframeActionTarget;
}

interface State {
  src: string;
  showIframe: boolean;
}

export default class PresentationIframe extends Component<Props> {
  static getDerivedStateFromProps(props: Props, state: State): Partial<State> {
    const newState: Partial<State> = {};

    if (props.src !== state.src) {
      newState.src = props.src;
      newState.showIframe = false;
    }

    return newState;
  }

  state: State = {
    src: '',
    showIframe: false,
  };

  private _iframeLink?: IframeComlink;

  componentDidMount() {
    this.props.actionTarget.addEventListener('action', this._onAction);
  }

  componentWillUnmount() {
    this.props.actionTarget.removeEventListener('action', this._onAction);
  }

  private _onAction = (event: import('./').IframeActionEvent) => {
    if (!this._iframeLink) return;
    this._iframeLink[event.action]();
  };

  private _onIframeLoad = (event: Event) => {
    const el = event.currentTarget as HTMLIFrameElement;

    if (this._iframeLink) this._iframeLink[comlink.releaseProxy]();

    this._iframeLink = comlink.wrap(
      comlink.windowEndpoint(el.contentWindow!),
    ) as IframeComlink;

    this.setState({ showIframe: true });
  };

  private _onTransition = async (el: HTMLElement): Promise<void> => {
    const outgoing = el.children[0] as HTMLElement;

    if (outgoing.nodeName === 'IFRAME') {
      return animate(
        outgoing,
        { to: { opacity: '0' } },
        // easeInOutCubic
        { duration: 500, easing: 'cubic-bezier(0.645, 0.045, 0.355, 1)' },
      );
    }
  };

  render(_: Props, { src, showIframe }: State) {
    return (
      <div class="presentation-iframe">
        <Transition onTransition={this._onTransition}>
          {src ? (
            <iframe
              key={src}
              class={showIframe ? 'show' : ''}
              src={src}
              onLoad={this._onIframeLoad}
            ></iframe>
          ) : (
            <div />
          )}
        </Transition>
      </div>
    );
  }
}