package com.turingdi.awp.router.api;

import com.turingdi.awp.router.SubRouter;
import com.turingdi.awp.util.common.Constants;
import com.turingdi.awp.util.common.NetworkUtils;
import com.turingdi.awp.util.common.TuringBase64Util;
import io.vertx.core.Future;
import io.vertx.core.Vertx;
import io.vertx.core.eventbus.Message;
import io.vertx.core.http.HttpServerRequest;
import io.vertx.core.http.HttpServerResponse;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.RoutingContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;

import static com.turingdi.awp.entity.db.Account.JsonKey.WXAPPID;
import static com.turingdi.awp.entity.db.Account.JsonKey.WXAPPSECRET;
import static com.turingdi.awp.router.EventBusNamespace.*;
import static com.turingdi.awp.util.common.Constants.*;

/**
 * 微信授权的Controller/SubRouter
 *
 * @author Leibniz.Hu
 * Created on 2017-09-26 16:54.
 */
public class WechatOauthSubRouter implements SubRouter {
    private Logger log = LoggerFactory.getLogger(getClass());
    private Vertx vertx = Constants.vertx();
    private Router wxOauthRouter;

    private static final String WECHAT_JSON_OPENID_KEY = "openid";
    private static final String WECHAT_JSON_ERRCODE_KEY = "errcode";
    private static final String WECHAT_JSON_ACCESSTOKEN_KEY = "access_token";

    public static Router create(){
        return new WechatOauthSubRouter().subRouter();
    }

    private WechatOauthSubRouter(){
        wxOauthRouter = Router.router(vertx);
        wxOauthRouter.get("/apply/:body").handler(this::applyForOauth);//申请微信授权
        wxOauthRouter.route("/baseCb").handler(this::oauthBaseCallback);//静默授权回调
        wxOauthRouter.route("/infoCb").handler(this::oauthInfoCallback);//用户信息授权回调
    }

    @Override
    public Router subRouter() {
        return wxOauthRouter;
    }

    /**
     * 申请微信授权
     * /awp/wxOauth/apply/{body}
     * web服务需要授权时,向用户发送重定向,重定向到当前接口
     * 参数只有一个,内容为JSON,请用http://localhost:8083/awp/base64.html进行加密
     * {
     * "eid":web项目使用的公众号在本项目中的用户ID
     * "type":0=静默授权,只能获取OpenID,1=正常授权,会弹出授权确认页面,可以获取到用户信息
     * "callback":授权成功后调用的web项目回调接口地址,请使用完整地址,
     * 回调时会使用GET方法,加上rs参数,
     * 如果静默授权,rs参数内容就是openid
     * 如果正常授权,rs参数内容是turingBase64加密的授权结果(JSON)
     * }
     *
     * @param rc Vertx的RoutingContext对象
     * @author Leibniz.Hu
     */
    private void applyForOauth(RoutingContext rc) {
        HttpServerResponse resp = rc.response();
        String decodedBody = TuringBase64Util.decode(rc.request().getParam("body"));
        JsonObject reqJson = new JsonObject(decodedBody);
        Integer eid = reqJson.getInteger("eid");
        int type = reqJson.getInteger("type");
        String callback = TuringBase64Util.encode(reqJson.getString("callback"));//授权后回调方法
        vertx.eventBus().<JsonObject>send(ADDR_ACCOUNT_DB.get(), makeMessage(COMMAND_GET_ACCOUNT_BY_ID, eid), ar -> {
            if (ar.succeeded()) {
                JsonObject account = ar.result().body();
                String redirectAfterUrl = PROJ_URL + "oauth/wx/" + (type == 0 ? "baseCb" : "infoCb") + "?eid=" + eid + "&visitUrl=" + callback;
                String returnUrl = null;
                try {
                    returnUrl = String.format((type == 0 ? OAUTH_BASE_API : OAUTH_INFO_API)
                            , account.getString(WXAPPID), URLEncoder.encode(redirectAfterUrl, "UTF-8"));
                } catch (UnsupportedEncodingException ignored) { //不可能出现的
                }
                resp.setStatusCode(302).putHeader("Location", returnUrl).end();
            } else {
                log.error("EventBus消息响应错误", ar.cause());
                resp.setStatusCode(500).end("EventBus error!");
            }
        });
    }

    /**
     * 微信静默授权的回调方法
     * 由微信服务器调用
     *
     * @param rc Vertx的RoutingContext对象
     * @author Leibniz.Hu
     */
    private void oauthBaseCallback(RoutingContext rc) {
        HttpServerRequest request = rc.request();
        HttpServerResponse response = rc.response();
        String code = request.getParam("code");
        Integer eid = Integer.parseInt(request.getParam("eid"));
        log.debug("微信静默授权回调方法接收到请求:code={},远程地址={},远程域名={},绝对URI={}", code, request.remoteAddress(), request.host(), request.absoluteURI());
        assert code != null;
        Future.<Message<JsonObject>>future(f ->
                vertx.eventBus().send(ADDR_ACCOUNT_DB.get(), makeMessage(COMMAND_GET_ACCOUNT_BY_ID, eid), f)
        ).compose(msg -> Future.<JsonObject>future(f -> {
                    JsonObject account = msg.body();
                    String openIdUrl = String.format(OPENID_API, account.getString(WXAPPID), account.getString(WXAPPSECRET), code);
                    NetworkUtils.asyncPostJson(openIdUrl, f);
                })
        ).setHandler(res -> {
            if (res.succeeded()) {
                JsonObject openIdJson = res.result();
                log.debug("授权返回的json数据:{}", openIdJson);
                //重定向到原访问URL
                if (openIdJson.containsKey(WECHAT_JSON_OPENID_KEY)) {
                    String openId = openIdJson.getString(WECHAT_JSON_OPENID_KEY);
                    String visitUrl = request.getParam("visitUrl");//getRedirectAddress(request, REMOVE_PARAMS);
                    if (visitUrl.length() > 0) {
                        visitUrl = TuringBase64Util.decode(visitUrl).replaceAll("[\\s*\t\n\r]", "");
                        log.info("授权成功,OpenID={},准备跳转到{}", openId, visitUrl);
                        response.setStatusCode(302).putHeader("Location", visitUrl + (visitUrl.contains("?") ? "&rs=" : "?rs=") + TuringBase64Util.encode(openIdJson.toString())).end();
                    } else {
                        log.error("没有找到授权后回调地址" + request.absoluteURI());
                        response.end("未设置授权后回调地址");
                    }
                } else if (openIdJson.containsKey(WECHAT_JSON_ERRCODE_KEY)) {
                    //有错误
                    response.setStatusCode(302).putHeader("Location", PROJ_URL + "static/pageerror.html?st=8&errmsg=" + openIdJson.getString("errmsg")).end();
                }
            } else {
                log.error("抛出异常", res.cause());
                response.setStatusCode(500).end();
            }
        });
    }

    /**
     * 微信普通授权(获取用户信息)的回调方法
     * 由微信服务器调用
     *
     * @param rc Vertx的RoutingContext对象
     * @author Leibniz.Hu
     */
    private void oauthInfoCallback(RoutingContext rc) {
        HttpServerRequest request = rc.request();
        HttpServerResponse response = rc.response();
        String code = request.getParam("code");
        Integer eid = Integer.parseInt(request.getParam("eid"));
        log.debug("微信普通授权回调方法接收到请求:code={},远程地址={},远程域名={},绝对URI={}", code, request.remoteAddress(), request.host(), request.absoluteURI());
        assert code != null;
        Future.<Message<JsonObject>>future(f ->
                vertx.eventBus().send(ADDR_ACCOUNT_DB.get(), makeMessage(COMMAND_GET_ACCOUNT_BY_ID, eid), f)
        ).compose(msg -> Future.<JsonObject>future(f -> {
                    JsonObject account = msg.body();
                    String openIdUrl = String.format(OPENID_API, account.getString(WXAPPID), account.getString(WXAPPSECRET), code);
                    NetworkUtils.asyncPostJson(openIdUrl, f);
                })
        ).compose(openIdJson -> Future.<JsonObject>future(f -> {
                    log.debug("授权返回的json数据:{}", openIdJson);
                    if (openIdJson.containsKey(WECHAT_JSON_OPENID_KEY)) {
                        String openId = openIdJson.getString(WECHAT_JSON_OPENID_KEY);
                        String userinfo_url = String.format(USERINFO_API, openIdJson.getString(WECHAT_JSON_ACCESSTOKEN_KEY), openId);
                        NetworkUtils.asyncPostJson(userinfo_url, f);
                    }
                })
        ).setHandler(res -> {
            if (res.succeeded()) {
                JsonObject userInfoJson = res.result();
                //重定向到原访问URL
                String visitUrl = request.getParam("visitUrl");//getRedirectAddress(request, REMOVE_PARAMS);
                if (visitUrl.length() > 0) {
                    if (userInfoJson.size() > 0) {
                        visitUrl = TuringBase64Util.decode(visitUrl).replaceAll("[\\s*\t\n\r]", "");
                        log.debug("当前授权的用户信息:{}", userInfoJson.toString());
                        response.setStatusCode(302).putHeader("Location", visitUrl + (visitUrl.contains("?") ? "&rs=" : "?rs=") + TuringBase64Util.encode(userInfoJson.toString())).end();
                    } else {
                        response.setStatusCode(302).putHeader("Location", visitUrl).end();
                    }
                } else {
                    log.error("没有找到授权后回调地址" + request.absoluteURI());
                    response.end("未设置授权后回调地址");
                }
            } else {
                log.error("抛出异常", res.cause());
                response.setStatusCode(500).end();
            }
        });
    }
}