package com.zhiqiyun.open.router.apis;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.dliyun.oap.framework.annotation.ServiceMethod;
import com.dliyun.oap.framework.annotation.ServiceMethodBean;
import com.dliyun.oap.framework.response.OapResponse;
import com.zhiqiyun.open.core.service.SystemConfigService;
import com.zhiqiyun.open.router.request.EmptyRequest;
import com.zhiqiyun.open.router.request.oauth2.*;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;

import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

@Slf4j
@ServiceMethodBean
public class Oauth2Api {

    @Autowired
    private OkHttpClient okHttpClient;

    @Autowired
    private SystemConfigService systemConfigService;

    /**
     * 调试成功
     *
     * @param request
     * @return
     * @throws IOException
     */
    @ServiceMethod(method = "oauth2.login", title = "用户密码登录")
    public OapResponse login(Oauth2LoginRequest request) throws IOException {

        String hostAddress = this.systemConfigService.getStringValue("OAUTH2_API_CONFIG", "hostAddress");
        String clientSecret = this.systemConfigService.getStringValue("OAUTH2_API_CONFIG", "clientSecret");

        Map<String, String> paramValues = new HashMap<>();
        paramValues.put("grant_type", "password");
        paramValues.put("scope", "all");
        paramValues.put("username", request.getUserName());
        paramValues.put("password", DigestUtils.md5Hex(request.getPassword()));
        paramValues.put("login_type", request.getLoginType());
        paramValues.put("type", "account");

        log.info(JSON.toJSONString(paramValues));

        FormBody.Builder formBuilder = new FormBody.Builder();
        paramValues.forEach(formBuilder::add);


        Request.Builder builder = new Request.Builder();
        builder.url(String.format("%s/blade-auth/oauth/token", hostAddress));
        builder.header("Authorization", "Basic " + clientSecret);
        builder.header("Content-Type", "application/x-www-form-urlencoded");
        builder.post(formBuilder.build());
        Response resp = this.okHttpClient.newCall(builder.build()).execute();
        if (resp.isSuccessful()) {
            String result = Objects.requireNonNull(resp.body()).string();
            JSONObject jsonObject = JSON.parseObject(result);
            return OapResponse.success().setBody(jsonObject);
        } else {
            try {
                String result = Objects.requireNonNull(resp.body()).string();
                log.error(result);
                JSONObject jsonObject = JSON.parseObject(result);
                return OapResponse.fail(jsonObject.getString("error"), jsonObject.getString("error_description"));
            } catch (Exception e) {
                log.error("", e);
                return OapResponse.fail("NETWORK_ERROR", "网络异常" + resp.message());
            }
        }
    }

    /**
     * 调试成功
     *
     * @param request
     * @return
     * @throws IOException
     */
    @ServiceMethod(method = "oauth2.account.info", title = "获取用户信息")
    public OapResponse userInfo(Oauth2UserInfoRequest request) throws IOException {


        String hostAddress = this.systemConfigService.getStringValue("OAUTH2_API_CONFIG", "hostAddress");
        String clientSecret = this.systemConfigService.getStringValue("OAUTH2_API_CONFIG", "clientSecret");

        Request.Builder builder = new Request.Builder();
        builder.url(String.format("%s/blade-user/account/info", hostAddress));
        builder.header("Authorization", "Basic " + clientSecret);
        builder.header("Blade-Auth", "bearer " + request.getAccessToken());
        builder.header("Content-Type", "application/x-www-form-urlencoded");

        return this.getResponse(builder);
    }

    /**
     * 已经对接成功
     *
     * @param request
     * @return
     * @throws IOException
     */
    @ServiceMethod(method = "oauth2.validate.token", title = "验证登录状态")
    public OapResponse validateToken(Oauth2ValidateTokenRequest request) throws IOException {

        String hostAddress = this.systemConfigService.getStringValue("OAUTH2_API_CONFIG", "hostAddress");
        String clientSecret = this.systemConfigService.getStringValue("OAUTH2_API_CONFIG", "clientSecret");
        RequestBody requestBody = RequestBody.create("{}", MediaType.parse("application/json; charset=utf-8"));

        Request.Builder builder = new Request.Builder();
        builder.url(String.format("%s/blade-auth/validate/token", hostAddress));
        builder.header("Authorization", "Basic " + clientSecret);
        builder.header("Blade-Auth", "bearer " + request.getAccessToken());
        builder.header("Content-Type", "application/json");
        builder.post(requestBody);

        return this.getResponse(builder);
    }

    /**
     * 已经对接成功
     *
     * @param request
     * @return
     * @throws IOException
     */
    @ServiceMethod(method = "oauth2.wechat.login", title = "微信授权登录")
    public OapResponse oauthWechatLogin(Oauth2WechatMpLoginRequest request) throws IOException {

        String hostAddress = this.systemConfigService.getStringValue("OAUTH2_API_CONFIG", "hostAddress");
        String clientSecret = this.systemConfigService.getStringValue("OAUTH2_API_CONFIG", "clientSecret");

        Request.Builder builder = new Request.Builder();

        HttpUrl.Builder urlBuilder = Objects.requireNonNull(HttpUrl.parse(String.format("%s/blade-auth/oauth/auth-login/%s", hostAddress, request.getSource()))).newBuilder();
        urlBuilder.addQueryParameter("uuid", request.getUuid());
        urlBuilder.addQueryParameter("name", request.getName());
        urlBuilder.addQueryParameter("realName", request.getRealName());
        if (request.getSex() != null) {
            urlBuilder.addQueryParameter("sex", request.getSex().toString());
        }
        urlBuilder.addQueryParameter("email", request.getEmail());
        urlBuilder.addQueryParameter("phone", request.getPhone());

        log.info(urlBuilder.build().toString());
        builder.url(urlBuilder.build());
        builder.header("Authorization", "Basic " + clientSecret);
        builder.header("Content-Type", "application/x-www-form-urlencode");
        builder.get();

        return this.getResponse(builder);
    }

    /**
     * 已经对接成功
     *
     * @param request
     * @return
     * @throws IOException
     */
    @ServiceMethod(method = "oauth2.register", title = "注册用户")
    public OapResponse oauthRegister(Oauth2RegisterRequest request) throws IOException {

        String hostAddress = this.systemConfigService.getStringValue("OAUTH2_API_CONFIG", "hostAddress");
        String clientSecret = this.systemConfigService.getStringValue("OAUTH2_API_CONFIG", "clientSecret");

        Map<String, String> paramValues = new HashMap<>();
        paramValues.put("account", request.getAccount());
        paramValues.put("password", DigestUtils.md5Hex(request.getPassword()));

        RequestBody requestBody = RequestBody.create(JSON.toJSONString(paramValues), MediaType.parse("application/json; charset=utf-8"));

        Request.Builder builder = new Request.Builder();
        builder.url(String.format("%s/blade-user/account/submit", hostAddress));
        builder.header("Authorization", "Basic " + clientSecret);
        builder.header("Content-Type", "application/json");
        builder.post(requestBody);

        return this.getResponse(builder);
    }

    /**
     * 已经对接成功
     *
     * @param request
     * @return
     * @throws IOException
     */
    @ServiceMethod(method = "oauth2.update.info", title = "更新用户信息")
    public OapResponse oauthUpdateInfo(Oauth2UpdateInfoRequest request) throws IOException {

        String hostAddress = this.systemConfigService.getStringValue("OAUTH2_API_CONFIG", "hostAddress");
        String clientSecret = this.systemConfigService.getStringValue("OAUTH2_API_CONFIG", "clientSecret");

        Map<String, String> paramValues = new HashMap<>();
        paramValues.put("name", request.getName());
        paramValues.put("realName", request.getRealName());
        if (request.getSex() != null) {
            paramValues.put("sex", request.getSex().toString());
        }
        if (StringUtils.isNotBlank(request.getEmail())) {
            paramValues.put("email", request.getEmail());
        }
        if (StringUtils.isNotBlank(request.getPhone())) {
            paramValues.put("phone", request.getPhone());
        }
        if (StringUtils.isNotBlank(request.getPassword())) {
            paramValues.put("password", DigestUtils.md5Hex(request.getPassword()));
        }
        RequestBody requestBody = RequestBody.create(JSON.toJSONString(paramValues), MediaType.parse("application/json; charset=utf-8"));

        Request.Builder builder = new Request.Builder();
        builder.url(String.format("%s/blade-user/account/update-info", hostAddress));
        builder.header("Authorization", "Basic " + clientSecret);
        builder.header("Blade-Auth", "bearer " + request.getAccessToken());
        builder.header("Content-Type", "application/json");
        builder.post(requestBody);

        return this.getResponse(builder);
    }

    /**
     * 已经对接成功
     *
     * @param request
     * @return
     * @throws IOException
     */
    @ServiceMethod(method = "oauth2.update.password", title = "修改密码")
    public OapResponse oauthUpdatePassword(Oauth2UpdatePasswordRequest request) throws IOException {

        String hostAddress = this.systemConfigService.getStringValue("OAUTH2_API_CONFIG", "hostAddress");
        String clientSecret = this.systemConfigService.getStringValue("OAUTH2_API_CONFIG", "clientSecret");

        Map<String, String> paramValues = new HashMap<>();
        paramValues.put("oldPassword", DigestUtils.md5Hex(request.getOldPassword()));
        paramValues.put("newPassword", DigestUtils.md5Hex(request.getNewPassword()));

        FormBody.Builder formBuilder = new FormBody.Builder();
        paramValues.forEach(formBuilder::add);

        Request.Builder builder = new Request.Builder();
        builder.url(String.format("%s/blade-user/account/update-password", hostAddress));
        builder.header("Authorization", "Basic " + clientSecret);
        builder.header("Blade-Auth", "bearer " + request.getAccessToken());
        builder.header("Content-Type", "application/x-www-form-urlencode");
        builder.post(formBuilder.build());

        return this.getResponse(builder);
    }

    @ServiceMethod(method = "oauth2.social.submit", title = "新增用户")
    public OapResponse oauthSocialSubmit(Oauth2SocialSubmitRequest request) throws IOException {

        String hostAddress = this.systemConfigService.getStringValue("OAUTH2_API_CONFIG", "hostAddress");
        String clientSecret = this.systemConfigService.getStringValue("OAUTH2_API_CONFIG", "clientSecret");

        Map<String, String> paramValues = new HashMap<>();
        paramValues.put("account", request.getAccount());
        paramValues.put("password", DigestUtils.md5Hex(request.getPassword()));
        paramValues.put("name", request.getName());
        paramValues.put("realName", request.getRealName());
        if (request.getSex() != null) {
            paramValues.put("sex", request.getSex().toString());
        }
        paramValues.put("email", request.getEmail());
        paramValues.put("phone", request.getPhone());

        log.debug(JSON.toJSONString(paramValues));
        RequestBody requestBody = RequestBody.create(JSON.toJSONString(paramValues), MediaType.parse("application/json; charset=utf-8"));

        Request.Builder builder = new Request.Builder();
        builder.url(String.format("%s/blade-user/social/submit", hostAddress));
        builder.header("Authorization", "Basic " + clientSecret);
        builder.header("Blade-Auth", "bearer " + request.getAccessToken());
        builder.header("Content-Type", "application/json");
        builder.post(requestBody);

        return this.getResponse(builder);
    }

    @ServiceMethod(method = "oauth2.social.update", title = "修改用户")
    public OapResponse oauthSocialUpdate(Oauth2SocialUpdateRequest request) throws IOException {

        String hostAddress = this.systemConfigService.getStringValue("OAUTH2_API_CONFIG", "hostAddress");
        String clientSecret = this.systemConfigService.getStringValue("OAUTH2_API_CONFIG", "clientSecret");

        Map<String, String> paramValues = new HashMap<>();
        paramValues.put("id", request.getId().toString());
        paramValues.put("name", request.getName());
        paramValues.put("realName", request.getRealName());
        if (request.getSex() != null) {
            paramValues.put("sex", request.getSex().toString());
        }
        if (StringUtils.isNotBlank(request.getPassword())) {
            paramValues.put("password", DigestUtils.md5Hex(request.getPassword()));
        }
        paramValues.put("email", request.getEmail());
        paramValues.put("phone", request.getPhone());

        log.debug(JSON.toJSONString(paramValues));
        RequestBody requestBody = RequestBody.create(JSON.toJSONString(paramValues), MediaType.parse("application/json; charset=utf-8"));

        Request.Builder builder = new Request.Builder();
        builder.url(String.format("%s/blade-user/social/update", hostAddress));
        builder.header("Authorization", "Basic " + clientSecret);
        builder.header("Blade-Auth", "bearer " + request.getAccessToken());
        builder.header("Content-Type", "application/json");
        builder.post(requestBody);

        return this.getResponse(builder);
    }

    @ServiceMethod(method = "oauth2.social.remove", title = "删除用户")
    public OapResponse oauthSocialRemove(Oauth2SocialRemoveRequest request) throws IOException {

        String hostAddress = this.systemConfigService.getStringValue("OAUTH2_API_CONFIG", "hostAddress");
        String clientSecret = this.systemConfigService.getStringValue("OAUTH2_API_CONFIG", "clientSecret");

        Map<String, String> paramValues = new HashMap<>();
        paramValues.put("id", request.getId().toString());

        log.debug(JSON.toJSONString(paramValues));

        FormBody.Builder formBuilder = new FormBody.Builder();
        paramValues.forEach(formBuilder::add);

        Request.Builder builder = new Request.Builder();
        builder.url(String.format("%s/blade-user/social/remove", hostAddress));
        builder.header("Authorization", "Basic " + clientSecret);
        builder.header("Blade-Auth", "bearer " + request.getAccessToken());
        builder.header("Content-Type", "application/x-www-form-urlencode");
        builder.post(formBuilder.build());

        return this.getResponse(builder);
    }

    @ServiceMethod(method = "oauth2.get.image.captcha", title = "获取发送手机验证码的图形验证码")
    public OapResponse oauthGetImageCaptcha(EmptyRequest request) throws IOException {

        String hostAddress = this.systemConfigService.getStringValue("OAUTH2_API_CONFIG", "hostAddress");
        String clientSecret = this.systemConfigService.getStringValue("OAUTH2_API_CONFIG", "clientSecret");

        Request.Builder builder = new Request.Builder();
        builder.url(String.format("%s/blade-resource/sms/open/endpoint/send-captcha", hostAddress));
        builder.header("Authorization", "Basic " + clientSecret);
        builder.header("Content-Type", "application/x-www-form-urlencode");
        builder.get();

        return this.getResponse(builder);
    }


    @ServiceMethod(method = "oauth2.send.phone.validate.code", title = "发送短信验证码")
    public OapResponse oauthSendPhoneValidateCode(Oauth2SendPhoneValidateCodeRequest request) throws IOException {

        String hostAddress = this.systemConfigService.getStringValue("OAUTH2_API_CONFIG", "hostAddress");
        String clientSecret = this.systemConfigService.getStringValue("OAUTH2_API_CONFIG", "clientSecret");

        HttpUrl.Builder urlBuilder = Objects.requireNonNull(HttpUrl.parse(String.format("%s/blade-resource/sms/open/endpoint/send-validate", hostAddress))).newBuilder();
        urlBuilder.addQueryParameter("phone", request.getPhone());
        urlBuilder.addQueryParameter("captchaKey", request.getCaptchaKey());
        urlBuilder.addQueryParameter("captchaCode", request.getCaptchaCode());


        log.info(">>>>>{}", urlBuilder.build());
        Request.Builder builder = new Request.Builder();
        builder.url(urlBuilder.build());
        builder.header("Authorization", "Basic " + clientSecret);
        builder.header("Content-Type", "application/x-www-form-urlencode");
        builder.get();

        return this.getResponse(builder);
    }

    @ServiceMethod(method = "oauth2.phone.login", title = "手机验证码登录")
    public OapResponse oauthPhoneLogin(Oauth2PhoneLoginRequest request) throws IOException {

        String hostAddress = this.systemConfigService.getStringValue("OAUTH2_API_CONFIG", "hostAddress");
        String clientSecret = this.systemConfigService.getStringValue("OAUTH2_API_CONFIG", "clientSecret");

        HttpUrl.Builder urlBuilder = Objects.requireNonNull(HttpUrl.parse(String.format("%s/blade-auth/oauth/phone-login", hostAddress))).newBuilder();
        urlBuilder.addQueryParameter("phone", request.getPhone());
        urlBuilder.addQueryParameter("code", request.getCode());
        urlBuilder.addQueryParameter("id", request.getId());

        log.info(urlBuilder.build().toString());

        Request.Builder builder = new Request.Builder();
        builder.url(urlBuilder.build());
        builder.header("Authorization", "Basic " + clientSecret);
        builder.header("Content-Type", "application/x-www-form-urlencode");
        builder.get();

        return this.getResponse(builder);
    }

    @ServiceMethod(method = "oauth2.forget.password", title = "用户忘记密码修改密码")
    public OapResponse oauthForgetPassword(Oauth2ForgetPasswordRequest request) throws IOException {

        String hostAddress = this.systemConfigService.getStringValue("OAUTH2_API_CONFIG", "hostAddress");
        String clientSecret = this.systemConfigService.getStringValue("OAUTH2_API_CONFIG", "clientSecret");

        Map<String, String> paramValues = new HashMap<>();
        paramValues.put("phone", request.getPhone());
        paramValues.put("code", request.getCode());
        paramValues.put("id", request.getId());
        paramValues.put("password", DigestUtils.md5Hex(request.getPassword()));

        log.debug(JSON.toJSONString(paramValues));

        FormBody.Builder formBuilder = new FormBody.Builder();
        paramValues.forEach(formBuilder::add);

        RequestBody requestBody = RequestBody.create(JSON.toJSONString(paramValues), MediaType.parse("application/json; charset=utf-8"));
        Request.Builder builder = new Request.Builder();
        builder.url(String.format("%s/blade-user/social/reset-password", hostAddress));
        builder.header("Authorization", "Basic " + clientSecret);
        builder.header("Content-Type", "application/json");
        builder.post(requestBody);

        return this.getResponse(builder);
    }

    private OapResponse getResponse(Request.Builder builder) throws IOException {
        log.info(JSON.toJSONString(builder));
        Response resp = this.okHttpClient.newCall(builder.build()).execute();
        String body = Objects.requireNonNull(resp.body()).string();
        log.info(body);
        if (resp.isSuccessful()) {
            JSONObject jsonObject = JSON.parseObject(body);
            String code = jsonObject.getString("code");
            String msg = jsonObject.getString("msg");
            JSONObject data = jsonObject.getJSONObject("data");

            if (StringUtils.equals("200", code)) {
                return OapResponse.success().setBody(data);
            }
            return OapResponse.fail("REMOTE_ERROR_" + code, msg);
        } else {
            if (Arrays.asList(401, 400).contains(resp.code())) {
                JSONObject object = JSON.parseObject(body);
                String msg = object.getString("msg");
                if (StringUtils.isBlank(msg)) {
                    msg = object.getString("error_description");
                }
                return OapResponse.fail("ERROR", msg);
            } else {
                return OapResponse.fail("NETWORK_ERROR", resp.message());
            }
        }
    }
}
