package com.sonic.lion.domain.enums;

import com.sonic.lion.enums.TradeStatus;
import org.apache.commons.lang3.StringUtils;

import java.util.HashMap;
import java.util.Map;

/**
 * @author: code
 * @date: 2025/06/10
 * @Description: 调用支付渠道状态
 * @version: 1.0.0
 */
public enum CallChannelStatus {

    /**
     * 初始化，准备提交请求
     */
    INIT(0, "INIT"),

    /**
     * 已提交请求，渠道处理中
     */
    PROCESSING(1, "PROCESSING"),

    /**
     * 渠道处理成功
     */
    SUCC(2, "SUCC"),

    /**
     * 渠道处理失败
     */
    FAIL(3, "FAIL"),

    /**
     * 请求取消
     */
    CANCEL(4, "CANCEL"),

    /**
     * 出现异常，情况未知
     */
    UNKNOW(5, "UNKNOW"),

    EXPIRED(6, "EXPIRED");

    private final int value;

    private final String desc;

    CallChannelStatus(int value, String desc) {
        this.value = value;
        this.desc = desc;
    }

    public static CallChannelStatus fromPayssionRefund(String state) {
        Map<String, CallChannelStatus> map = new HashMap<String, CallChannelStatus>() {
            {
                put("refunded", CallChannelStatus.SUCC);
                put("refund_pending", CallChannelStatus.PROCESSING);
                put("Card refund_failed", CallChannelStatus.FAIL);
                put("refund_cancelled", CallChannelStatus.CANCEL);
            }
        };
        return map.get(state) == null ? CallChannelStatus.PROCESSING : map.get(state);
    }

    public int getValue() {
        return value;
    }

    public String getDesc() {
        return desc;
    }

    public static CallChannelStatus get(int value) {
        for (CallChannelStatus callChannelStatus : values()) {
            if (callChannelStatus.getValue() == value) {
                return callChannelStatus;
            }
        }
        return null;
    }

    private static final Map<CallChannelStatus, TradeStatus> channelTradeStatusMaps = new HashMap<CallChannelStatus, TradeStatus>() {
        {
            put(CallChannelStatus.INIT, TradeStatus.WAITPAY);
            put(CallChannelStatus.PROCESSING, TradeStatus.PROCESSING);
            put(CallChannelStatus.SUCC, TradeStatus.FINISHED);
            put(CallChannelStatus.FAIL, TradeStatus.CLOSED);
            put(CallChannelStatus.CANCEL, TradeStatus.CLOSED);
            put(CallChannelStatus.UNKNOW, TradeStatus.CLOSED);
            put(CallChannelStatus.EXPIRED, TradeStatus.CLOSED);
        }
    };


    private static final Map<String, CallChannelStatus> callChannelStatusMap = new HashMap<String, CallChannelStatus>() {
        {
            // 创建成功
            put("CREATED", CallChannelStatus.PROCESSING);
            // 订单已保存并保留
            put("SAVED", CallChannelStatus.PROCESSING);
            // 支付成功 客户通过贝宝（PayPal）钱包或其他形式的客人或非品牌付款批准了付款。例如，卡，银行帐户
            put("APPROVED", CallChannelStatus.SUCC);
            // 付款已被授权或已为订单捕获授权付款
            put("COMPLETED", CallChannelStatus.SUCC);
            // 订单中的所有购买单位均作废
            put("VOIDED", CallChannelStatus.FAIL);

            //apture_status
            // 退款已取消
            put("CANCELLED", CallChannelStatus.SUCC);
            // 退款中 尚未记入收款人的PayPal帐户
            put("PENDING", CallChannelStatus.PROCESSING);
            // 退款完成  记入收款人的PayPal帐户
            put("COMPLETED", CallChannelStatus.SUCC);
            // 部分退款已到账
            put("PARTIALLY_REFUNDED", CallChannelStatus.SUCC);
            // 已退回
            put("REFUNDED", CallChannelStatus.FAIL);
            // 退款异常
            put("FAILED", CallChannelStatus.FAIL);
            // 资金无法收回
            put("DECLINED", CallChannelStatus.FAIL);
//			在状态为PENDING或者DECLINED,reason的值可能是以下几种
//
//			1.BUYER_COMPLAINT。付款人与贝宝（PayPal）对此捕获的付款提出了争议。
//			2.CHARGEBACK。响应于付款人与用于支付此已捕获付款的金融工具的发行人对此已捕获的付款提出异议，已收回的资金被撤回。
//			3.ECHECK。由尚未结清的电子支票支付的付款人。
//			4.INTERNATIONAL_WITHDRAWAL。访问您的在线帐户。在您的“帐户概览”中，接受并拒绝此笔付款。
//			5.OTHER。无法提供其他特定原因。有关此笔付款的更多信息，请在线访问您的帐户或联系PayPal。
//			6.PENDING_REVIEW。捕获的付款正在等待人工审核。
//			7.RECEIVING_PREFERENCE_MANDATES_MANUAL_ACTION。收款人尚未为其帐户设置适当的接收首选项。有关如何接受或拒绝此付款的更多信息，请在线访问您的帐户。通常在某些情况下提供此原因，例如当所捕获付款的货币与收款人的主要持有货币不同时。
//			8.REFUNDED。收回的资金已退还。
//			9.TRANSACTION_APPROVED_AWAITING_FUNDING。付款人必须将这笔付款的资金汇出。通常，此代码适用于手动EFT。
//			10.UNILATERAL。收款人没有PayPal帐户。
//			11.VERIFICATION_REQUIRED。收款人的PayPal帐户未通过验证。
//

            //apture_status

            put("ONHOLD", CallChannelStatus.PROCESSING);
            //payout
            // 支出已取消
            put("NEW", CallChannelStatus.PROCESSING);
            // 支出中 您的付款要求已收到，将尽快处理
            put("PENDING", CallChannelStatus.PROCESSING);
            // 支出完成  资金已记入收件人的帐户
            put("SUCCESS", CallChannelStatus.SUCC);
            // 此支出的接收者没有PayPal帐户。贝宝向收件人发送了注册链接以创建帐户。如果收款人未在30天内创建帐户并要求付款，则资金将退还到您的帐户中
            put("UNCLAIMED", CallChannelStatus.PROCESSING);
            // 支出已退回
            put("REFUNDED", CallChannelStatus.FAIL);
            //拒绝
            put("DENIED", CallChannelStatus.FAIL);
            put("FAILURE", CallChannelStatus.FAIL);
            put("BLOCKED", CallChannelStatus.FAIL);
            put("REVERSED", CallChannelStatus.FAIL);
            put("RETURNED", CallChannelStatus.FAIL);
        }
    };

    public static TradeStatus toTradeStatus(CallChannelStatus callChannelStatus) {
        return channelTradeStatusMaps.get(callChannelStatus);
    }


    public static CallChannelStatus from(String orderStatus) {
        CallChannelStatus callChannelStatus = callChannelStatusMap.get(orderStatus);
        return callChannelStatus == null ? CallChannelStatus.PROCESSING : callChannelStatus;
    }

    public static CallChannelStatus fromCheckout(String orderStatus) {
        /**
         * "Pending" "Authorized" "Card Verified" "Voided" "Partially Captured" "Captured" "Partially Refunded" "Refunded" "Declined" "Canceled" "Expired" "Paid"
         */
        Map<String, CallChannelStatus> map = new HashMap<String, CallChannelStatus>() {
            {
                put("Pending", CallChannelStatus.PROCESSING);
                put("Authorized", CallChannelStatus.PROCESSING);
                put("Card Verified", CallChannelStatus.PROCESSING);

                put("Voided", CallChannelStatus.FAIL);
                put("Partially Captured", CallChannelStatus.PROCESSING);
                put("Captured", CallChannelStatus.SUCC);

                put("Partially Refunded", CallChannelStatus.FAIL);
                put("Refunded", CallChannelStatus.FAIL);
                put("Declined", CallChannelStatus.FAIL);
                put("Canceled", CallChannelStatus.CANCEL);

                put("Expired", CallChannelStatus.EXPIRED);
                put("Paid", CallChannelStatus.PROCESSING);
            }
        };
        return map.get(orderStatus) == null ? CallChannelStatus.PROCESSING : map.get(orderStatus);
    }

    public static CallChannelStatus fromPayssion(String orderStatus) {
        /**
         *     error	支付发生错误
         *     pending	未完成支付
         *     completed	支付成功
         *     paid_partial	部分支付，用户只支付了部分金额
         *     awaiting_confirm	待确认，系统风控自动拦截
         *     failed	支付失败
         *     cancelled	交易被取消
         *     expired	交易过期
         *     refunded	退款成功
         *     refund_pending	已申请退款，正在处理退款
         *     refund_failed	退款失败
         *     refund_cancelled	退款已取消
         *     chargeback	拒付
         */
        Map<String, CallChannelStatus> map = new HashMap<String, CallChannelStatus>() {
            {
                put("error", CallChannelStatus.FAIL);
                put("pending", CallChannelStatus.PROCESSING);
                put("completed", CallChannelStatus.SUCC);

                put("paid_partial", CallChannelStatus.PROCESSING);
                put("awaiting_confirm", CallChannelStatus.PROCESSING);
                put("failed", CallChannelStatus.FAIL);

                put("cancelled", CallChannelStatus.CANCEL);
                put("expired", CallChannelStatus.EXPIRED);
                put("chargeback", CallChannelStatus.FAIL);
            }
        };
        return map.get(orderStatus) == null ? CallChannelStatus.PROCESSING : map.get(orderStatus);
    }

    /**
     * 将airwallex的状态转换成系统内的状态
     * @param orderStatus                   一级状态
     * @param latestPaymentAttemptStatus    最新的二级子状态
     * @param latestPaymentAttemptFailureCode                   最新的二级子状态对应的异常码
     * @return
     */
    public static CallChannelStatus fromAirwallex(String orderStatus, String latestPaymentAttemptStatus, String latestPaymentAttemptFailureCode) {
        /**
         * REQUIRES_PAYMENT_METHOD
         *      Populate payment_method when calling confirm
         *      This value is returned if payment_method is either null, or the payment_method has failed during confirm, and a different payment_method should be provided.
         *
         * REQUIRES_CUSTOMER_ACTION
         *      Pending customer action, see next_action for details. Possible causes are pending 3DS authentication, QR code scan.
         *
         * REQUIRES_CAPTURE
         *      Pending manual capture, which is required after calling confirm with auto_capture=false.
         *
         * PENDING
         *      he payment request has been accepted. Waiting for the final result.
         *
         * CANCELLED
         *      The PaymentIntent has been cancelled. The amount authorized but not captured will be returned.
         *
         * SUCCEEDED
         *      The payment was successful, no further action required.
         */
        Map<String, CallChannelStatus> map = new HashMap<String, CallChannelStatus>() {
            {
                put("REQUIRES_PAYMENT_METHOD", CallChannelStatus.PROCESSING);

                put("REQUIRES_CUSTOMER_ACTION", CallChannelStatus.PROCESSING);
                put("REQUIRES_CAPTURE", CallChannelStatus.PROCESSING);
                put("PENDING", CallChannelStatus.PROCESSING);

                put("CANCELLED", CallChannelStatus.CANCEL);
                put("SUCCEEDED", CallChannelStatus.SUCC);
            }
        };
        //付款尝试状态类型列表
        //判断付款参数状态（子状态）的异常类型（当子状态为关闭、过期、失败时，直接转换对应的支付状态返回）
        Map<String, CallChannelStatus> latestPaymentAttemptStatusMap = new HashMap<String, CallChannelStatus>() {
            {
                put("CANCELLED", CallChannelStatus.CANCEL);
                put("EXPIRED", CallChannelStatus.EXPIRED);
                put("FAILED", CallChannelStatus.FAIL);
            }
        };
        //fix_6.29.0 判断子状态如果为识别，且异常码为 时，处理成 PROCESSING 状态 【场景：用户付款先3DS验证失败，然后再验证成功并成功付款的场景】
        if("FAILED".equals(latestPaymentAttemptStatus) && "authentication_failed".equals(latestPaymentAttemptFailureCode)) {
            return CallChannelStatus.PROCESSING;
        }
        //子状态的终态转换
        if(StringUtils.isNotEmpty(latestPaymentAttemptStatus) && latestPaymentAttemptStatusMap.get(latestPaymentAttemptStatus) != null) {
            return latestPaymentAttemptStatusMap.get(latestPaymentAttemptStatus);
        }
        //主状态的状态转换
        CallChannelStatus callChannelStatus = map.get(orderStatus) == null ? CallChannelStatus.PROCESSING : map.get(orderStatus);
        return callChannelStatus;
    }

    public static CallChannelStatus fromTipalti(String status) {
        Map<String, CallChannelStatus> map = new HashMap<String, CallChannelStatus>() {
            {
                put("Rejected", CallChannelStatus.FAIL);
                put("Paid", CallChannelStatus.SUCC);
                put("Cleared", CallChannelStatus.SUCC);

                put("Deferred", CallChannelStatus.FAIL);
                put("Canceled", CallChannelStatus.FAIL);
                put("Deferred (Internal)", CallChannelStatus.FAIL);
            }
        };
        return map.get(status) == null ? CallChannelStatus.PROCESSING : map.get(status);
    }
}
