package pro.shushi.pamirs.thirdparty.core.dingtalk.controller;

import com.alibaba.fastjson.JSON;
import com.aliyun.dingtalkcontact_1_0.models.GetUserHeaders;
import com.aliyun.dingtalkcontact_1_0.models.GetUserResponseBody;
import com.aliyun.dingtalkoauth2_1_0.models.GetUserTokenRequest;
import com.aliyun.dingtalkoauth2_1_0.models.GetUserTokenResponse;
import com.aliyun.teautil.models.RuntimeOptions;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import pro.shushi.pamirs.meta.annotation.fun.extern.Slf4j;
import pro.shushi.pamirs.meta.api.dto.model.PamirsUserDTO;
import pro.shushi.pamirs.meta.api.session.PamirsSession;
import pro.shushi.pamirs.resource.api.enmu.UserSignUpType;
import pro.shushi.pamirs.thirdparty.core.dingtalk.helper.DingTalkHelper;
import pro.shushi.pamirs.user.api.cache.UserCache;
import pro.shushi.pamirs.user.api.constants.UserConstant;
import pro.shushi.pamirs.user.api.enmu.UserSourceEnum;
import pro.shushi.pamirs.user.api.enmu.UserThirdPartyTypeEnum;
import pro.shushi.pamirs.user.api.login.UserCookieLoginSimple;
import pro.shushi.pamirs.user.api.login.UserInfoCache;
import pro.shushi.pamirs.user.api.model.PamirsUser;
import pro.shushi.pamirs.user.api.model.PamirsUserThirdParty;
import pro.shushi.pamirs.user.api.service.PasswordService;
import pro.shushi.pamirs.user.api.utils.CookieUtil;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * 服务端API身份验证（免登）使用教程实现登录第三方网站
 * https://open.dingtalk.com/document/orgapp/tutorial-obtaining-user-personal-information
 */
@Slf4j
@RestController
@RequestMapping(value = "/pamirs")
public class DingTalkAuthController {

    @Value("${pamirs.dingtalk.clientId}")
    private String clientId;

    @Value("${pamirs.dingtalk.clientSecret}")
    private String clientSecret;

    @Value("${pamirs.dingtalk.redirectUrl}")
    private String redirectUri;

    @Value("${pamirs.dingtalk.appUrl}")
    private String appUrl;

    @Autowired
    private PasswordService passwordService;

    /**
     * 心跳检查URI
     * @return
     */
    @RequestMapping(value = "/ddAuth/check", method = RequestMethod.GET)
    public String ok() {
        return "ok";
    }

    /**
     * 第一步：构建授权链接并重定向到钉钉登录页面
     */
    @RequestMapping(value = "/ddAuth/oauth", method = RequestMethod.GET)
    public void oauth(HttpServletResponse response) throws IOException {
        String url = "https://login.dingtalk.com/oauth2/auth?" +
                "redirect_uri=" + appUrl + "/pamirs/ddAuth/oauth2url" +
                "&response_type=code" +
                "&client_id=" + clientId +  //应用的AppKey
                "&scope=openid" + //此处的openId保持不变
                "&state=dd1" +    //跟随authCode原样返回。
                "&prompt=consent";
        response.sendRedirect(url);
    }

    /**
     * 第二步：处理钉钉回调，获取 authCode 并换取 accessToken
     */
    @RequestMapping(value = "/ddAuth/oauth2url", method = RequestMethod.GET)
    public void handleCallback(@RequestParam(value = "authCode")String authCode,HttpServletResponse response) throws Exception {
        com.aliyun.dingtalkoauth2_1_0.Client client = DingTalkHelper.authClient();
        log.info("钉钉回传authCode:{}", authCode);
        GetUserTokenRequest getUserTokenRequest = new GetUserTokenRequest()
                // 应用基础信息-应用信息的AppKey,请务必替换为开发的应用AppKey
                .setClientId(clientId)
                // 应用基础信息-应用信息的AppSecret，,请务必替换为开发的应用AppSecret
                .setClientSecret(clientSecret)
                .setCode(authCode)
                .setGrantType("authorization_code");
        GetUserTokenResponse getUserTokenResponse = client.getUserToken(getUserTokenRequest);
        String accessToken = getUserTokenResponse.getBody().getAccessToken();

        // 使用 AccessToken 获取用户信息
        getUserinfo(accessToken);

        // 重定向回应用首页
        response.sendRedirect(appUrl);
    }

    /**
     * 第三步：使用 accessToken 获取用户个人信息
     */
    public void getUserinfo(String accessToken) throws Exception {
        com.aliyun.dingtalkcontact_1_0.Client client = DingTalkHelper.contactClient();
        GetUserHeaders getUserHeaders = new GetUserHeaders();
        getUserHeaders.xAcsDingtalkAccessToken = accessToken;
        // 获取用户个人信息，如需获取当前授权人的信息，unionId参数必须传me
        GetUserResponseBody userResponseBody = client.getUserWithOptions("me", getUserHeaders, new RuntimeOptions()).getBody();
        // 处理获取到的远端用户数据 & Cookie
        handleUserInfoAndCookie(userResponseBody, accessToken);

        if (log.isDebugEnabled()) {
            log.debug("个人信息：{}", JSON.toJSONString(userResponseBody));
        }
    }

    /**
     * 第四步：处理用户信息并设置登录态（Session + Cookie）
     */
    public void handleUserInfoAndCookie(GetUserResponseBody userResponseBody, String accessToken) {
        if (userResponseBody == null) {
            return;
        }
        PamirsUser user = new PamirsUser().setLogin(userResponseBody.getMobile()).queryOne();
        boolean needInitPwd = false;
        if (user == null) {
            user = new PamirsUser();
            needInitPwd = true;
        }
        user.setLogin(userResponseBody.getMobile());
        user.setPhone(userResponseBody.getMobile());
        user.setNickname(userResponseBody.getNick());
        user.setName(userResponseBody.getNick());
        user.setAvatarUrl(userResponseBody.getAvatarUrl());
        user.setEmail(userResponseBody.getEmail());
        user.setActive(Boolean.TRUE);
        user.setSource(UserSourceEnum.THIRD_PARTY);
        user.setSignUpType(UserSignUpType.BACKSTAGE);
        user.setUserType("dingtalk");
        user.createOrUpdate();
        // 初始化密码表
        if (needInitPwd) {
            passwordService.encodingCreate(user.getId(), "123456@Abc!");
        }
        // 第三方用户三方登录表
        PamirsUserThirdParty userThirdParty = new PamirsUserThirdParty().setThirdPartyType(UserThirdPartyTypeEnum.DINGTALK)
                .setUnionId(userResponseBody.getUnionId()).queryOne();
        if (userThirdParty == null) {
            PamirsUserThirdParty thirdParty = new PamirsUserThirdParty();
            thirdParty.setUserId(user.getId());
            thirdParty.setOpenid(userResponseBody.getOpenId());
            thirdParty.setUnionId(userResponseBody.getUnionId());
            thirdParty.setThirdPartyType(UserThirdPartyTypeEnum.DINGTALK);
            thirdParty.createOrUpdate();
        }
        // 用户信息更新后清空缓存
        UserInfoCache.clearUserById(user.getId());

        PamirsUserDTO pamirsUser = new PamirsUserDTO();
        pamirsUser.setUserId(user.getId());
        pamirsUser.setUserCode(user.getCode());
        pamirsUser.setUserName(user.getName());
        pamirsUser.setEmail(user.getEmail());
        pamirsUser.setPhone(user.getPhone());
        pamirsUser.setLangCode("zh-CN");

        String sessionId = PamirsSession.getSessionId();
        HttpServletResponse httpServletResponse = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
        UserCookieLoginSimple userCookieLoginSimple = new UserCookieLoginSimple();
        if(StringUtils.isBlank(sessionId)){
            sessionId = userCookieLoginSimple.createSessionId();
        }
        String cacheKey = userCookieLoginSimple.parseSessionId(sessionId);
        UserCache.putCache(cacheKey, pamirsUser);
        try {
            CookieUtil.set(httpServletResponse, UserConstant.USER_SESSION_ID, sessionId);
            // 用户落库的情况下，可以不用设置ddtoken到Cookie中,也可以设置。
            // CookieUtil.set(httpServletResponse, "ddtoken", accessToken);
        } catch (Exception e) {
            log.error("SSO Login Cookie Set Err", e);
        }
    }
}
