package org.maxkey.web.contorller;

import com.alibaba.cloud.commons.lang.StringUtils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.dingtalk.api.DefaultDingTalkClient;
import com.dingtalk.api.DingTalkClient;
import com.dingtalk.api.request.OapiGettokenRequest;
import com.dingtalk.api.response.OapiGettokenResponse;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.nimbusds.jwt.SignedJWT;
import com.taobao.api.ApiException;
import io.swagger.annotations.ApiOperation;
import org.maxkey.authn.AbstractAuthenticationProvider;
import org.maxkey.authn.LoginCredential;
import org.maxkey.authn.realm.jdbc.JdbcAuthenticationRealm;
import org.maxkey.authn.support.jwt.JwtLoginService;
import org.maxkey.authn.support.socialsignon.service.SocialSignOnProviderService;
import org.maxkey.authn.support.socialsignon.service.SocialsAssociateService;
import org.maxkey.authz.cas.endpoint.ticket.generator.DefaultUniqueTicketIdGenerator;
import org.maxkey.constants.ConstantsLoginType;
import org.maxkey.entity.*;
import org.maxkey.persistence.db.LoginHistoryService;
import org.maxkey.persistence.redis.RedisConnection;
import org.maxkey.persistence.redis.RedisConnectionFactory;
import org.maxkey.persistence.service.HistorySystemLogsService;
import org.maxkey.persistence.service.OrganizationsService;
import org.maxkey.persistence.service.UserInfoService;
import org.maxkey.util.JsonUtils;
import org.maxkey.util.RetCode;
import org.maxkey.web.WebConstants;
import org.maxkey.web.WebContext;
import org.maxkey.web.component.TreeNode;
import org.maxkey.web.component.TreeNodeList;
import org.maxkey.web.endpoint.LoginEndpoint;
import org.maxkey.web.message.MessageType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.web.bind.annotation.*;
import org.maxkey.util.RetResult;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@RestController
@RequestMapping("/thirdLogin")
public class ThirdLoginController
{
    private static Logger _logger = LoggerFactory.getLogger(LoginEndpoint.class);

    @Autowired
    @Qualifier("authenticationProvider")
    AbstractAuthenticationProvider authenticationProvider;

    @Autowired
    @Qualifier("jwtLoginService")
    JwtLoginService jwtLoginService;

    @Autowired
    @Qualifier("authenticationRealm")
    JdbcAuthenticationRealm authenticationRealm;

    @Autowired
    OrganizationsService organizationsService;

    @Autowired
    @Qualifier("userInfoService")
    private UserInfoService userInfoService;

    @Autowired
    @Qualifier("socialSignOnProviderService")
    SocialSignOnProviderService socialSignOnProviderService;

    @Autowired
    SocialsAssociateService socialSignOnUserService;

    private DefaultUniqueTicketIdGenerator generator = new DefaultUniqueTicketIdGenerator();

    @Autowired
    RedisConnectionFactory redisConnectionFactory;

    @Autowired
    LoginHistoryService loginHistoryService;


    /**
     * init login
     *
     * @return
     */
    @ApiOperation(value = "登录接口", notes = "用户登录地址", httpMethod = "GET")
    @RequestMapping(value = {"/login"})
    public RetResult login(@RequestParam("username") String username, @RequestParam("password") String password, HttpServletRequest request) throws JsonProcessingException {
        RetResult result = new RetResult();
        Map<String, Object> data = new HashMap<String, Object>();
//        //获取一个参数
//        String username = request.getParameter("username");
//        //获取所有参数
//        String password = request.getParameter("password");
        _logger.debug("third login 。。。");
        UserInfo userInfo = authenticationProvider.loadUserInfo(username, password);
        _logger.debug("user info " + userInfo);
        if (null != userInfo && authenticationRealm.passwordMatches(userInfo, password))
        {
            String token = jwtLoginService.buildLoginJwt();
            data.put("userInfo", userInfo);
            data.put("token", token);
            RedisConnection redisConnection = redisConnectionFactory.getConnection();
            // 默认 7天
            // 先获取之前有没有token
            String oldToken = redisConnection.get(userInfo.getId());
            if (StringUtils.isNotEmpty(oldToken))
            {
                redisConnection.delete(userInfo.getId());
                redisConnection.delete(oldToken);
            }
            ObjectMapper objectMapper = new ObjectMapper();
            redisConnection.setex(userInfo.getId(), 60 * 60 * 24 * 7, token);
            redisConnection.setex(token, 60 * 60 * 24 * 7, objectMapper.writeValueAsString(userInfo));
            redisConnection.close();
            _logger.debug("token >>>" + objectMapper.writeValueAsString(userInfo));
            _logger.debug("token >>>" + token);

            // 登录
            // 认证信息
            LoginCredential loginCredential = new LoginCredential(
                    userInfo.getUsername(), "", ConstantsLoginType.JWT);
            authenticationProvider.authentication(loginCredential, true);
            data.put("sessionId", request.getSession().getId());
            loginHistoryService.login(userInfo, WebContext.genId(), ConstantsLoginType.JWT, "success", "", "", "", "", 1);

            result.setData(data);
            result.setCode(RetCode.SUCCESS);
            return result;
        }

        result = new RetResult();
        result.setCode(RetCode.FAIL);
        result.setMsg("用户不存在");
        return result;
    }

    /**
     * 根据token获取令牌
     *
     * @param token
     * @return
     */
    @RequestMapping(value = {"/getTicket"})
    public RetResult<Object> getTicket(HttpServletRequest request)
    {
        JSONObject result = new JSONObject();
        String token = request.getHeader("Authorization");
        _logger.debug("token > " + token);
        // 生成令牌
        String ticket = generator.getNewTicketId("TT");
        _logger.debug("ticket > " + ticket);
        // 1天
        RedisConnection redisConnection = redisConnectionFactory.getConnection();
        String userInfo = redisConnection.get(token);
        if (StringUtils.isEmpty(userInfo))
        {
            return new RetResult().setMsg("请求失败，token无效").setData(null).setCode(RetCode.SUCCESS);
        }
        Jackson2JsonRedisSerializer<UserInfo> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<UserInfo>(UserInfo.class);
        UserInfo user = JSONObject.parseObject(userInfo, UserInfo.class);
        result.put("token", token);
        result.put("userInfo", user);

        redisConnection.setex(ticket, 60 * 60 * 24 * 1, result.toString());
        redisConnection.close();
        result = new JSONObject();
        result.put("ticket", ticket);
        return new RetResult().setMsg("请求成功").setData(result).setCode(RetCode.SUCCESS);
    }

    /**
     * 根据令牌获取用户信息
     *
     * @param ticket
     * @return
     */
    @RequestMapping(value = {"/getUserInfo"}, method = RequestMethod.GET)
    public RetResult<Object> getUserInfo(@RequestParam("ticket") String ticket, HttpServletRequest request)
    {
        if (StringUtils.isEmpty(ticket))
        {
            return new RetResult().setMsg("参数ticket不存在").setData(null).setCode(RetCode.FAIL);
        }

        JSONObject result = new JSONObject();
        RedisConnection redisConnection = redisConnectionFactory.getConnection();
        String userInfo = redisConnection.get(ticket);
        JSONObject userObject = JSONObject.parseObject(userInfo);
        result.put("userInfo", JSONObject.toJSONString(userObject.get("userInfo")));
        result.put("token", userObject.getString("token"));
        result.put("sessionId", request.getSession().getId());
        redisConnection.close();
        return new RetResult().setMsg("请求成功").setData(result).setCode(RetCode.SUCCESS);
    }

    /**
     * 根据钉钉ID获取用户信息
     *
     * @param userid
     * @return
     */
    @RequestMapping(value = {"/getUserInfoByDingId"}, method = RequestMethod.GET)
    public RetResult<Object> getUserInfoByDingId(@RequestParam("userid") String userid, HttpServletRequest request)
    {
        if (StringUtils.isEmpty(userid))
        {
            return new RetResult().setMsg("参数userid不存在").setData(null).setCode(RetCode.FAIL);
        }
        String accessToken = "";
        try
        {
            accessToken = getAccessToken();
        } catch (Exception e)
        {

        }
        UserInfo info = userInfoService.getMapper().queryUserInfoByAssociateId(userid);
        JSONObject result = new JSONObject();
        result.put("userInfo", info);
        result.put("accessToken", accessToken);
        return new RetResult().setMsg("请求成功").setData(result).setCode(RetCode.SUCCESS);
    }

    /**
     * 获取accessToken
     *
     * @return
     * @throws ApiException
     */
    public String getAccessToken() throws ApiException
    {
        SocialsProvider socialSignOnProvider = socialSignOnProviderService.get("dingtalk");
        DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/gettoken");
        OapiGettokenRequest request = new OapiGettokenRequest();
        request.setAppkey(socialSignOnProvider.getClientId());
        request.setAppsecret(socialSignOnProvider.getClientSecret());
        request.setHttpMethod("GET");
        OapiGettokenResponse response = client.execute(request);
        return response.getAccessToken();
    }

    /**
     * 校验token
     *
     * @param token
     * @return
     */
    @RequestMapping(value = {"/checkJwtToken"})
    public RetResult checkJwtToken(@RequestParam("token") String token)
    {
        SignedJWT jwtToken = jwtLoginService.jwtTokenValidation(token);
        _logger.debug("token > " + token + "jwtToken >" + jwtToken);
        if (null != jwtToken)
        {
            return new RetResult().setCode(RetCode.SUCCESS);
        }
        return new RetResult().setMsg("token出错").setCode(RetCode.FAIL);
    }

    @RequestMapping(value = {"/usersList"})
    public RetResult usersList()
    {
        List<UserInfo> users = userInfoService.query(null);

        return new RetResult().setMsg("请求成功").setData(users).setCode(RetCode.SUCCESS);
    }

    /**
     * 部门树集合
     *
     * @param id
     * @return
     */
    @GetMapping({"/organizationsTree"})
    public List<HashMap<String, Object>> organizationsTree(HttpServletRequest request, @RequestParam(value = "id", required = false) String id)
    {
        String authorization = request.getHeader("Authorization");
        String user = request.getHeader("user");
        _logger.debug("authorization id :" + authorization);
        _logger.debug("organizationsTree id :" + id);
        _logger.debug("user :" + user);
        Organizations queryOrg = new Organizations();
        List<Organizations> organizationsList = this.organizationsService.queryOrgs(queryOrg);
        TreeNodeList treeNodeList = new TreeNodeList();

        for (Organizations org : organizationsList)
        {
            TreeNode treeNode = new TreeNode(org.getId(), org.getName());
            if (org.getHasChild() != null && org.getHasChild().startsWith("Y"))
            {
                treeNode.setHasChild();
            }

            treeNode.setAttr("data", org);
            treeNode.setPId(org.getParentId());
            if (org.getId().equals("1"))
            {
                treeNode.setAttr("open", Boolean.valueOf(true));
            } else
            {
                treeNode.setAttr("open", Boolean.valueOf(false));
            }
            treeNodeList.addTreeNode(treeNode.getAttr());
        }

        return treeNodeList.getTreeNodeList();
    }


    /**
     * 获取第三方登录信息
     * dingtalk: /logon/oauth20/authorize/dingtalk
     */
    @GetMapping({"/loadSocials"})
    public RetResult loadSocials()
    {
        List<SocialsProvider> socialsProviderList = socialSignOnProviderService.getSocialSignOnProviders();
        RetResult result = new RetResult();
        result.setCode(RetCode.SUCCESS);
        result.setMsg("查询成功");
        result.setData(socialsProviderList);
        return result;
    }


}
