package com.wecloud.im.server.handler;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.socket.nio.NioSocketChannel;
import lombok.extern.slf4j.Slf4j;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Component;

import com.wecloud.im.core.common.api.ApiCode;
import com.wecloud.im.core.common.exception.BusinessException;
import com.wecloud.im.core.common.exception.DaoException;
import com.wecloud.im.core.common.exception.SpringBootPlusException;
import com.wecloud.im.core.exception.VerificationCodeException;
import com.wecloud.im.core.util.JsonUtils;
import com.wecloud.im.server.model.WsResponse;
import com.wecloud.im.server.sender.ChannelSender;
import com.wecloud.netty.dispatch.common.BaseRequest;
import com.wecloud.netty.dispatch.extend.ActionMessage;
import com.wecloud.netty.dispatch.extend.ArgumentBox;
import com.wecloud.netty.dispatch.extend.impl.DefaultArgumentBox;
import com.wecloud.netty.dispatch.general.config.GeneralActionDispatcher;
import com.wecloud.netty.dispatch.general.extend.ActionMessageResolver;


/**
 * @author lixiaozhong
 */
@Component
@Slf4j
public class GeneralMessageHandler {

    @Autowired
    private GeneralActionDispatcher generalActionDispatcher;
    @Autowired
    private ActionMessageResolver actionMessageResolver;
    @Autowired
    private ChannelSender channelSender;

    public void doMessage(Long senderClientId, ChannelHandlerContext ctx, String data) {
        if (log.isDebugEnabled()) {
            log.debug("appWS收到data: {}\n senderClientId:{}, channelId:{}", data, senderClientId, ctx.channel().id().asLongText());
        }
        // 解析jsonO
        BaseRequest baseRequest = JsonUtils.decodeJson(data, BaseRequest.class);


        if (null == baseRequest || null == baseRequest.getAction()) {
            throw new BusinessException("null == baseRequest || null == baseRequest.getAction()");
        }

        ActionMessage am = actionMessageResolver.resolver(generalActionDispatcher, baseRequest);
        am.setSenderChannel(ctx.channel());
        am.setSenderClientId(senderClientId);

        Exception actionException = null;
        Object res = null;
        try {
            res = generalActionDispatcher.action(am);
        } catch (Exception ex) {
            actionException = ex;
        }
        log.info("调用完成");
        processDispatchResult(am, res, actionException);
    }

    public ArgumentBox getArgumentBox() {
        ArgumentBox beanBox = new DefaultArgumentBox();
        return beanBox;
    }


    private void processDispatchResult(ActionMessage am,
                                       @Nullable Object res,
                                       @Nullable Exception exception) {
        log.info("处理结果");

        if (exception != null) {
            log.error("dispatch action error:", exception);
            if (exception instanceof SpringBootPlusException) {
                // 处理自定义异常
                ApiCode errorCode;
                if (exception instanceof BusinessException) {
                    Integer apiCode = ((BusinessException) exception).getErrorCode();
                    if (apiCode == null) {
                        errorCode = ApiCode.BUSINESS_EXCEPTION;
                    } else {
                        errorCode = ApiCode.getApiCode(apiCode);
                    }
                } else if (exception instanceof DaoException) {
                    errorCode = ApiCode.DAO_EXCEPTION;
                } else if (exception instanceof VerificationCodeException) {
                    errorCode = ApiCode.VERIFICATION_CODE_EXCEPTION;
                } else {
                    errorCode = ApiCode.SPRING_BOOT_PLUS_EXCEPTION;
                }
                res = WsResponse.result(errorCode, exception.getMessage(), null).setReqId(am.getMessage().getReqId());
            } else {
                // 其他默认的全局异常处理
                res = WsResponse.result(ApiCode.SYSTEM_EXCEPTION, "", null).setReqId(am.getMessage().getReqId());
            }
        }
        if (res != null) {
            channelSender.sendMsgLocal((NioSocketChannel) am.getSenderChannel(), res);
        }
    }

}
