package com.liquidnet.service.account.wallet.controller;

import com.liquidnet.commons.lang.util.JsonUtils;
import com.liquidnet.service.account.common.ErrorConstants;
import com.liquidnet.service.account.wallet.dto.WalletEditResult;
import com.liquidnet.service.account.wallet.dto.WalletQueryResult;
import com.liquidnet.service.account.wallet.dto.WalletRegisterResult;
import com.liquidnet.service.account.wallet.dto.WalletTransactionResult;
import com.liquidnet.service.account.wallet.dto.base.WalletCallResult;
import com.liquidnet.service.account.wallet.dto.base.WalletContextParam;
import com.liquidnet.service.account.wallet.service.processor.WalletAccountEditProcessor;
import com.liquidnet.service.account.wallet.service.processor.WalletAccountQueryProcessor;
import com.liquidnet.service.account.wallet.service.processor.WalletAccountRegisterProcessor;
import com.liquidnet.service.account.wallet.service.processor.WalletTransactionProcessor;
import io.swagger.annotations.ApiOperation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;

import java.util.Arrays;

/**
 * WalletTransactionController.class
 *
 * @author zhanggb
 * Created by IntelliJ IDEA at 2020/10/23
 */
//@Api(tags = "Wallet Transmit")
//@RestController
//@RequestMapping("wl/tx")
public class WalletTransmitController {
    private static final Logger log = LoggerFactory.getLogger(WalletTransmitController.class);
    @Autowired
    private WalletAccountRegisterProcessor accountRegisterProcessor;
    @Autowired
    private WalletAccountEditProcessor accountEditProcessor;
    @Autowired
    private WalletAccountQueryProcessor accountQueryProcessor;
    @Autowired
    private WalletTransactionProcessor transactionProcessor;

    @ApiOperation(value = "Trading")
    @PostMapping("trading")
    public WalletCallResult<?> trading(@RequestBody String txData) {
        if (StringUtils.isEmpty(txData) || txData.length() <= 50) {
            log.warn(ErrorConstants.PARAMS_VALUE_ERROR_DESC);
            return new WalletCallResult<>(ErrorConstants.PARAMS_VALUE_ERROR_CODE, ErrorConstants.PARAMS_VALUE_ERROR_DESC);
        }
        String txStr = txData.substring(0, 50).trim(), txParameter;
        if (Arrays.stream(TxMethodEnum.values()).noneMatch(tx -> tx.name().equals(txStr))) {
            log.warn("Invalid txMethod[{}]", txStr);
            return new WalletCallResult<>(ErrorConstants.PARAMS_VALUE_ERROR_CODE, "Invalid method");
        }
        log.info("Call {}.parameters:[{}]", txStr, txParameter = txData.substring(50).trim());
        TxMethodEnum txMethodEnum = TxMethodEnum.valueOf(txStr.toUpperCase());
        WalletCallResult<?> result = null;
        WalletContextParam contextParam;
        try {
            contextParam = JsonUtils.fromJson(txParameter, WalletContextParam.class);
            switch (txMethodEnum) {
                case WalletRegisterParam:
                    contextParam.setTradeType(TxMethodEnum.WalletRegisterParam.name());
                    result = accountRegisterProcessor.service(contextParam);
                    result = result instanceof WalletRegisterResult ? (WalletRegisterResult) result : new WalletRegisterResult(result.getCode(), result.getMessage());
                    break;
                case WalletQueryParam:
                    contextParam.setTradeType(TxMethodEnum.WalletQueryParam.name());
                    result = accountQueryProcessor.service(contextParam);
                    result = result instanceof WalletQueryResult ? (WalletQueryResult) result : new WalletQueryResult(result.getCode(), result.getMessage());
                    break;
                case WalletEditParam:
                    contextParam.setTradeType(TxMethodEnum.WalletEditParam.name());
                    result = accountEditProcessor.service(contextParam);
                    result = result instanceof WalletEditResult ? (WalletEditResult) result : new WalletEditResult(result.getCode(), result.getMessage());
                    break;
                case WalletTransactionParam:
                    contextParam.setTradeType(TxMethodEnum.WalletTransactionParam.name());
                    result = transactionProcessor.service(contextParam);
                    result = result instanceof WalletTransactionResult ? (WalletTransactionResult) result : new WalletTransactionResult(result.getCode(), result.getMessage());
                    break;
                default:
                    result = new WalletCallResult<>(ErrorConstants.PARAMS_VALUE_ERROR_CODE, ErrorConstants.PARAMS_VALUE_ERROR_DESC);
                    break;
            }
        } catch (Exception e) {
            log.error("Call [{}] handle exception:[{}]", txStr, txParameter, e);
            switch (txMethodEnum) {
                case WalletRegisterParam:
                    result = new WalletRegisterResult(ErrorConstants.WALLET_CREATE_ERROR_CODE, ErrorConstants.WALLET_CREATE_ERROR_DESC);
                    break;
                case WalletQueryParam:
                    result = new WalletQueryResult(ErrorConstants.WALLET_QUERY_ERROR_CODE, ErrorConstants.WALLET_QUERY_ERROR_DESC);
                    break;
                case WalletEditParam:
                    result = new WalletEditResult(ErrorConstants.WALLET_EDIT_ERROR_CODE, ErrorConstants.WALLET_EDIT_ERROR_DESC);
                    break;
                case WalletTransactionParam:
                    result = new WalletTransactionResult(ErrorConstants.WALLET_TRANS_ERROR_CODE, ErrorConstants.WALLET_TRANS_ERROR_DESC);
                    break;
                default:
                    result = new WalletCallResult<>(ErrorConstants.SYSTEM_ERROR_CODE, ErrorConstants.SYSTEM_ERROR_DESC);
                    break;
            }
        }
        log.info("Call {}.result:[{}]", txStr, JsonUtils.toJson(result));
        return result;
    }

    private enum TxMethodEnum {
        WalletRegisterParam,
        WalletQueryParam,
        WalletEditParam,
        WalletTransactionParam;
    }
}
