package com.ruoyi.web.controller.dingding;

import com.aliyun.dingtalkcontact_1_0.models.GetUserHeaders;
import com.aliyun.dingtalkcontact_1_0.models.GetUserResponse;
import com.aliyun.dingtalkcontact_1_0.Client;
import com.aliyun.tea.TeaException;
import com.aliyun.teaopenapi.models.Config;
import com.aliyun.teautil.models.RuntimeOptions;
import com.dingtalk.api.DefaultDingTalkClient;
import com.dingtalk.api.DingTalkClient;
import com.dingtalk.api.request.OapiUserGetRequest;
import com.dingtalk.api.request.OapiUserGetuserinfoRequest;
import com.dingtalk.api.response.OapiUserGetResponse;
import com.dingtalk.api.response.OapiUserGetuserinfoResponse;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.dingding.config.DingUrlConstant;
import com.ruoyi.framework.web.service.SysLoginService;
import com.ruoyi.system.service.dingding.DingAuthService;
import com.ruoyi.system.service.dingding.DingTokenService;
import com.taobao.api.ApiException;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Optional;

/**
 * <p>DingLoginController 此类用于：钉钉企业内部应用免登（H5微应用）</p>
 * <p>@remark：钉钉企业内部微应用DEMO, 实现了身份验证（免登）功能</p>
 */
@Api(value = "dingAuthController", tags = "钉钉企业内部应用免登（H5微应用）")
@Controller
@RequestMapping(value = "/ding")
public class DingAuthController {


    @Resource
    private DingTokenService dingTokenService;

    @Resource
    private DingAuthService dingAuthService;

    @Autowired
    private SysLoginService loginService;

    /**
     * 钉钉用户登录，显示当前登录用户的userId和名称
     *
     * @param authCode 免登临时authCode
     * @return 当前用户
     */
    @ApiOperation(value = "钉钉用户登录，显示当前登录用户的userId和名称")
    @PostMapping("/avoidLogin")
    @ResponseBody
    public AjaxResult login(@RequestBody String authCode) {
        String accessToken;

        // 获取accessToken
        AjaxResult accessTokenSr = dingTokenService.getAccessToken();
        if (!accessTokenSr.isSuccess()) {
            return accessTokenSr;
        }
        accessToken = accessTokenSr.get(accessTokenSr.MSG_TAG).toString();

        // 获取用户userId
        AjaxResult userIdSr = getUserInfo(accessToken, authCode);
        if (!userIdSr.isSuccess()) {
            return userIdSr;
        }

        // 获取用户详情
        AjaxResult userInfo = this.getUser(accessToken, userIdSr.get(userIdSr.MSG_TAG).toString());

        return userInfo;
    }

    /**
     * 访问/user/getuserinfo接口获取用户userId
     *
     * @param accessToken access_token
     * @param authCode    临时授权码
     * @return 用户userId或错误信息
     */
    private AjaxResult getUserInfo(String accessToken, String authCode) {
        DingTalkClient client = new DefaultDingTalkClient(DingUrlConstant.URL_GET_USER_INFO);
        OapiUserGetuserinfoRequest request = new OapiUserGetuserinfoRequest();
        request.setCode(authCode);
        request.setHttpMethod("GET");
        OapiUserGetuserinfoResponse response;
        try {
            response = client.execute(request, accessToken);
        } catch (ApiException e) {
            return AjaxResult.error(e.getErrCode(), "Failed to getUserInfo: " + e.getErrMsg());
        }
        if (!response.isSuccess()) {
            return AjaxResult.error(response.getErrorCode(), response.getErrmsg());
        }
        return AjaxResult.success(response.getUserid());
    }


    /**
     * 访问/user/get 获取用户名称
     *
     * @param accessToken access_token
     * @param userId      用户userId
     * @return 用户名称或错误信息
     */
    private AjaxResult getUser(String accessToken, String userId) {
        DingTalkClient client = new DefaultDingTalkClient(DingUrlConstant.URL_USER_GET);
        OapiUserGetRequest request = new OapiUserGetRequest();
        request.setUserid(userId);
        request.setHttpMethod("GET");

        OapiUserGetResponse response;
        try {
            response = client.execute(request, accessToken);
        } catch (ApiException e) {
            return AjaxResult.error(Integer.parseInt(e.getErrCode()), "Failed to getUserName: " + e.getErrMsg());
        }

        SysUser user = this.assembleUserDTO(response, accessToken);

        return AjaxResult.success(user);
    }

    /**
     * 封装返回的用户信息
     *
     * @param response    response
     * @param accessToken accessToken
     * @return 用户信息
     */
    private SysUser assembleUserDTO(OapiUserGetResponse response, String accessToken) {
        String userid = response.getUserid();
        String mobile = response.getMobile();
        try {
            SysUser sysUser = Optional.ofNullable(dingAuthService.getUserByUserId(userid))
                    .orElse(dingAuthService.getUserByUsername(mobile));
            sysUser.setAccessToken(accessToken);
            sysUser.setNickName(response.getName());
            sysUser.setAvatar(response.getAvatar());
            return sysUser;
        } catch (Exception e) {
            return new SysUser();
        }
    }


    /**
     * 钉钉用户登录
     *
     * @param authCode 免登临时authCode
     * @return 当前用户
     */
    @ApiOperation(value = "钉钉用户登录")
    @PostMapping("/authToken2")
    @ResponseBody
    public AjaxResult authToken2(@RequestBody String authCode){
        // 获取accessToken
        try {
            AjaxResult accessTokenSr = dingTokenService.getUserAccessToken(authCode);

            Client client = this.createClient();
            GetUserHeaders getUserHeaders = new GetUserHeaders();
            getUserHeaders.xAcsDingtalkAccessToken = accessTokenSr.get(accessTokenSr.MSG_TAG).toString();
            try {
                GetUserResponse response = client.getUserWithOptions("me", getUserHeaders, new RuntimeOptions());
                accessTokenSr.put("sysUser",response.getBody());

                SysUser sysUser = dingAuthService.getUserByUsername(response.getBody().getMobile());

                if(StringUtils.isNull(sysUser) ){
                    // todo 生成用户信息进行登录

                }

                String token = loginService.authSingleSignIn(sysUser.getUserName());
                if (StringUtils.isNotEmpty(token)){
                    accessTokenSr.put(Constants.TOKEN, token);
                }
            } catch (TeaException e) {
                return AjaxResult.error(e.getMessage(),e);
            } catch (Exception e) {
                return AjaxResult.error(e.getMessage(),e);
            }
            return accessTokenSr;
        } catch (Exception e) {
            return AjaxResult.error("获取用户登录请求异常!");
        }
    }

    /**
     * 使用 Token 初始化账号Client
     * @return Client
     * @throws Exception
     */
    public static Client createClient() throws Exception {
        Config config = new Config();
        config.protocol = "https";
        config.regionId = "central";
        return new Client(config);
    }



}