import * as React from 'react';

import Loader from 'wix-style-react/dist/src/Loader';

import CashierPaymentsWidget from './../CashierPaymentsWidget/CashierPaymentsWidget';
import PaymentComplete from '../PaymentComplete/PaymentComplete';

import cashierPayments from 'cashier-payments-sdk/dist/src';

import {getParameterByName} from './../../utils/locationUtils';
import {postMessage} from './../../utils/communicationUtils';

class App extends React.Component {
  state = {
    isLoading: true,
    generalErrorMessage: '',
    order: null,
    paymentResult: null,
  };

  private params = {
    appId: '',
    appInstanceId: '',
    snapshotId: '',
    locale: 'en',
    visitorId: '',
    msid: '',
    cashierPCIUrl: undefined,
    walletExpressCheckoutAPIUrl: '/_api/payment-services-web/wallet/start?orderId={{orderId}}&paymentMethod={{paymentMethod}}',
    theme: 'default',
    showOnlyCurrentStep: undefined,
    host: null, // if host === '' - will be used host from window.location
    showThankYouPage: undefined, // true by default
  };

  rootNode;
  paymentWidget;

  constructor(props) {
    super(props);

    const href = window.location.href || '';
    Object.keys(this.params).forEach(key => {
      const param = getParameterByName(key, href);
      this.params[key] = param === null ? this.params[key] : param;
    });
    this.params.showOnlyCurrentStep = this.params.showOnlyCurrentStep === 'true' || this.params.theme === 'modal';
    this.params.host = this.params.host === null ? 'https://cashier-services.wix.com' : this.params.host;

    this.params.showThankYouPage = this.params.showThankYouPage !== 'false';
  }

  setPaymentWidgetRef = ref => {
    this.paymentWidget = ref;
  }

  setRootNode = node => {
    this.rootNode = node;
  }

  componentDidMount() {
    cashierPayments.getOrder(this.params.snapshotId, this.params.host).then(order => {
      this.setState({isLoading: false, order});
    }).catch(e => {
      this.setState({
        generalErrorMessage: 'Sorry, but something went wrong!'
      });
    });

    this.addListenerForMessagesFromParent();
    this.sendSizeNotification();
  }

  componentWillUnmount() {
    this.removeListenerForMessagesFromParent();
  }

  addListenerForMessagesFromParent = () => {
    window.addEventListener('resize', this.sendSizeNotification, false);
  }

  removeListenerForMessagesFromParent = () => {
    window.removeEventListener('resize', this.sendSizeNotification, false);
  }

  sendSizeNotification = () => {
    // because of tons of integrations and a lot of async's based on post messages
    // sometimes is happening case when we getting here just before dom will be updated, as a result we send
    // old size instead of new one
    // TODO this could be solved in more beautifull way after refactoring to callbacks system WCN-881
    setTimeout(() => {
      postMessage({
        type: 'SIZE',
        width: this.rootNode && this.rootNode.offsetWidth,
        height: this.rootNode && this.rootNode.offsetHeight,
      });
    }, 0);
  }

  handleError = (method, data) => {
    postMessage({
      type: 'PAYMENT_ERROR',
      method,
      error: data && data.toString && data.toString()
    });
  }

  handlePaymentResult = result => {
    this.sendSizeNotification();
  }

  handlePaymentMethodChanged = pmId => {
    this.sendSizeNotification();
    // we require to be sure, that component re-rendred with correct size
    setTimeout(() => {
      this.sendSizeNotification();
    }, 100);
  }

  handlePaymentComplete = (method, paymentResult) => {
    postMessage({
      type: 'PAYMENT_COMPLETE',
      method,
    });
    this.setState({paymentResult});
    this.sendSizeNotification();
  }

  handleReturn() {
    window.Wix.closeWindow();
  }

  render() {
    return (
      <div
        ref={this.setRootNode}
        data-hook="wcn-payment-app"
      >
        {this.renderLoading()}
        {this.renderGeneralError()}
        {this.renderPaymentWidget()}
        {this.renderPaymentComplete()}
      </div>
    );
  }

  renderLoading() {
    if (!this.state.isLoading || this.state.generalErrorMessage) {
      return null;
    }
    return (
      <div data-hook="wcn-spinner-main"><Loader size="medium"/></div>
    );
  }

  renderGeneralError() {
    const { generalErrorMessage } = this.state;
    if (!generalErrorMessage) {
      return null;
    }
    return (
      <div data-hook="wcn-general-error-message" role="alert">
        <span
          title={generalErrorMessage}
          >
          {generalErrorMessage}
        </span>
      </div>
    );
  }

  renderPaymentWidget() {
    if (this.state.isLoading || this.state.paymentResult) {
      return null;
    }
    const configuration = {
      appId: this.params.appId,
      appInstanceId: this.params.appInstanceId,
      snapshotId: this.params.snapshotId,
      locale: this.params.locale,
      visitorId: this.params.visitorId,
      msid: this.params.msid,
      cashierPCIUrl: this.params.cashierPCIUrl,
      walletExpressCheckoutAPIUrl: this.params.walletExpressCheckoutAPIUrl,
    };

    return (
      <CashierPaymentsWidget
        host={this.params.host}
        configuration={configuration}
        theme={this.params.theme}
        showOnlyCurrentStep={this.params.showOnlyCurrentStep || this.params.theme === 'modal'}
        ref={this.setPaymentWidgetRef}
        onError={this.handleError}
        paymentMethodChanged={this.handlePaymentMethodChanged}
        paymentResult={this.handlePaymentResult}
        onPaymentComplete={this.handlePaymentComplete}
      />
    );
  }

  renderPaymentComplete() {
    if (this.state.isLoading || !this.state.paymentResult) {
      return null;
    }
    if (!this.params.showThankYouPage) {
      this.handleReturn();
      return null;
    }
    return (
      <PaymentComplete
        order={this.state.order}
        paymentResult={this.state.paymentResult}
        locale={this.params.locale}
        onReturn={this.handleReturn}
      />
    );
  }
}

export default App;
