// Copyright 2022 The Casdoor Authors. 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 React from "react";
import {Button, Result} from "antd";
import Loading from "./common/Loading";
import * as PaymentBackend from "./backend/PaymentBackend";
import * as PricingBackend from "./backend/PricingBackend";
import * as SubscriptionBackend from "./backend/SubscriptionBackend";
import * as UserBackend from "./backend/UserBackend";
import * as Setting from "./Setting";
import i18next from "i18next";

class PaymentResultPage extends React.Component {
  constructor(props) {
    super(props);
    const params = new URLSearchParams(window.location.search);
    this.state = {
      classes: props,
      owner: props.match?.params?.organizationName ?? props.match?.params?.owner ?? null,
      paymentName: props.match?.params?.paymentName ?? null,
      pricingName: props.pricingName ?? props.match?.params?.pricingName ?? null,
      subscriptionName: params.get("subscription"),
      payment: null,
      pricing: props.pricing ?? null,
      subscription: props.subscription ?? null,
      timeout: null,
      user: null,
    };
  }

  UNSAFE_componentWillMount() {
    this.getPayment();
  }

  getUser() {
    UserBackend.getUser(this.props.account.owner, this.props.account.name)
      .then((res) => {
        if (res.data === null) {
          this.props.history.push("/404");
          return;
        }

        if (res.status === "error") {
          Setting.showMessage("error", res.msg);
          return;
        }

        this.setState({
          user: res.data,
        });
      });
  }

  componentWillUnmount() {
    if (this.state.timeout !== null) {
      clearTimeout(this.state.timeout);
    }
  }

  setStateAsync(state) {
    return new Promise((resolve, reject) => {
      this.setState(state, () => {
        resolve();
      });
    });
  }

  onUpdatePricing(pricing) {
    this.props.onUpdatePricing(pricing);
  }

  async getPayment() {
    if (!(this.state.owner && (this.state.paymentName || (this.state.pricingName && this.state.subscriptionName)))) {
      return ;
    }
    try {
      // loading price & subscription
      if (this.state.pricingName && this.state.subscriptionName) {
        if (!this.state.pricing) {
          const res = await PricingBackend.getPricing(this.state.owner, this.state.pricingName);
          if (res.status !== "ok") {
            throw new Error(res.msg);
          }
          const pricing = res.data;
          await this.setStateAsync({
            pricing: pricing,
          });
        }
        if (!this.state.subscription) {
          const res = await SubscriptionBackend.getSubscription(this.state.owner, this.state.subscriptionName);
          if (res.status !== "ok") {
            throw new Error(res.msg);
          }
          const subscription = res.data;
          await this.setStateAsync({
            subscription: subscription,
          });
        }
        const paymentName = this.state.subscription.payment;
        await this.setStateAsync({
          paymentName: paymentName,
        });
        this.onUpdatePricing(this.state.pricing);
      }
      const res = await PaymentBackend.getPayment(this.state.owner, this.state.paymentName);
      if (res.status !== "ok") {
        throw new Error(res.msg);
      }
      const payment = res.data;
      await this.setStateAsync({
        payment: payment,
      });
      if (payment.state === "Created") {
        if (["PayPal", "Stripe", "AirWallex", "Alipay", "WeChat Pay", "Balance", "Dummy"].includes(payment.type)) {
          this.setState({
            timeout: setTimeout(async() => {
              await PaymentBackend.notifyPayment(this.state.owner, this.state.paymentName);
              this.getPayment();
            }, 1000),
          });
        } else {
          this.setState({
            timeout: setTimeout(() => this.getPayment(), 1000),
          });
        }
      }

      if (payment.state === "Paid") {
        if (this.props.account) {
          this.getUser();
        }
      }
    } catch (err) {
      Setting.showMessage("error", err.message);
      return;
    }
  }

  goToViewOrder() {
    const payment = this.state.payment;
    if (payment && payment.order) {
      this.props.history.push(`/orders/${payment.owner}/${payment.order}/pay`);
    } else {
      Setting.showMessage("error", i18next.t("order:Order not found"));
    }
  }

  goToOrderList() {
    this.props.history.push("/orders");
  }

  render() {
    const payment = this.state.payment;

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

    if (payment.state === "Paid") {
      if (payment.isRecharge) {
        return (
          <div className="login-content">
            {
              Setting.renderHelmet(payment)
            }
            <Result
              status="success"
              title={`${i18next.t("payment:Recharged successfully")}`}
              subTitle={`${i18next.t("payment:You have successfully recharged")} ${payment.price} ${Setting.getCurrencyText(payment?.currency)}, ${i18next.t("payment:Your current balance is")} ${this.state.user?.balance} ${Setting.getCurrencyText(payment?.currency)}`}
              extra={[
                <Button type="primary" key="viewOrder" onClick={() => {
                  this.goToViewOrder();
                }}>
                  {i18next.t("order:View Order")}
                </Button>,
                <Button key="orderList" onClick={() => {
                  this.goToOrderList();
                }} style={{marginLeft: "10px"}}>
                  {i18next.t("order:Return to Order List")}
                </Button>,
              ]}
            />
          </div>
        );
      }
      return (
        <div className="login-content">
          {
            Setting.renderHelmet(payment)
          }
          <Result
            status="success"
            title={`${i18next.t("payment:You have successfully completed the payment")}: ${payment.productsDisplayName}`}
            subTitle={i18next.t("payment:You can view your order details or return to the order list")}
            extra={[
              <Button type="primary" key="viewOrder" onClick={() => {
                this.goToViewOrder();
              }}>
                {i18next.t("order:View Order")}
              </Button>,
              <Button key="orderList" onClick={() => {
                this.goToOrderList();
              }} style={{marginLeft: "10px"}}>
                {i18next.t("order:Return to Order List")}
              </Button>,
            ]}
          />
        </div>
      );
    } else if (payment.state === "Created") {
      return (
        <div className="login-content">
          {
            Setting.renderHelmet(payment)
          }
          <Result
            status="info"
            title={`${i18next.t("payment:The payment is still under processing")}: ${payment.productsDisplayName}, ${i18next.t("payment:the current state is")}: ${payment.state}, ${i18next.t("payment:please wait for a few seconds...")}`}
            subTitle={i18next.t("payment:You can view your order details or return to the order list")}
            extra={[
              <Loading key="returnUrl" tip={i18next.t("payment:Processing...")} style={{padding: "8px 0"}} />,
            ]}
          />
        </div>
      );
    } else if (payment.state === "Canceled") {
      return (
        <div className="login-content">
          {
            Setting.renderHelmet(payment)
          }
          <Result
            status="warning"
            title={`${i18next.t("payment:The payment has been canceled")}: ${payment.productsDisplayName}, ${i18next.t("payment:the current state is")}: ${payment.state}`}
            subTitle={i18next.t("payment:You can view your order details or return to the order list")}
            extra={[
              <Button type="primary" key="viewOrder" onClick={() => {
                this.goToViewOrder();
              }}>
                {i18next.t("order:View Order")}
              </Button>,
              <Button key="orderList" onClick={() => {
                this.goToOrderList();
              }} style={{marginLeft: "10px"}}>
                {i18next.t("order:Return to Order List")}
              </Button>,
            ]}
          />
        </div>
      );
    } else if (payment.state === "Timeout") {
      return (
        <div className="login-content">
          {
            Setting.renderHelmet(payment)
          }
          <Result
            status="warning"
            title={`${i18next.t("payment:The payment has timed out")}: ${payment.productsDisplayName}, ${i18next.t("payment:the current state is")}: ${payment.state}`}
            subTitle={i18next.t("payment:You can view your order details or return to the order list")}
            extra={[
              <Button type="primary" key="viewOrder" onClick={() => {
                this.goToViewOrder();
              }}>
                {i18next.t("order:View Order")}
              </Button>,
              <Button key="orderList" onClick={() => {
                this.goToOrderList();
              }} style={{marginLeft: "10px"}}>
                {i18next.t("order:Return to Order List")}
              </Button>,
            ]}
          />
        </div>
      );
    } else {
      return (
        <div className="login-content">
          {
            Setting.renderHelmet(payment)
          }
          <Result
            status="error"
            title={`${i18next.t("payment:The payment has failed")}: ${payment.productsDisplayName}, ${i18next.t("payment:the current state is")}: ${payment.state}`}
            subTitle={`${i18next.t("payment:Failed reason")}: ${payment.message}`}
            extra={[
              <Button type="primary" key="viewOrder" onClick={() => {
                this.goToViewOrder();
              }}>
                {i18next.t("order:View Order")}
              </Button>,
              <Button key="orderList" onClick={() => {
                this.goToOrderList();
              }} style={{marginLeft: "10px"}}>
                {i18next.t("order:Return to Order List")}
              </Button>,
            ]}
          />
        </div>
      );
    }
  }
}

export default PaymentResultPage;
