package com.sptg.gateway.controller.permissions;

import com.alibaba.fastjson.JSONObject;
import com.sptg.common.core.beans.ResultBean;
import com.sptg.common.core.beans.ResultEnum;
import com.sptg.common.core.constant.HttpConstant;
import com.sptg.common.core.constant.SysLogConstant;
import com.sptg.common.core.util.CookieUtils;
import com.sptg.common.core.util.WebUtils;
import com.sptg.common.security.annotation.Security;
import com.sptg.common.security.service.SecurityServiceInterface;
import com.sptg.permissions.api.dto.AccountOauthDto;
import com.sptg.permissions.api.dto.LoginDto;
import com.sptg.permissions.api.entity.Account;
import com.sptg.permissions.api.entity.AccountOauth;
import com.sptg.permissions.api.feigns.AccountAuthenticationFeign;
import com.sptg.permissions.api.feigns.AccountFeign;
import com.sptg.permissions.api.feigns.AccountOauthFeign;
import com.sptg.permissions.api.thirdauth.constants.CtwingAuthConstants;
import com.sptg.permissions.api.thirdauth.enums.AuthCustomizeSource;
import com.sptg.permissions.api.thirdauth.request.AuthCtwingRequest;
import com.sptg.permissions.api.thirdauth.util.ByteFormat;
import com.sptg.permissions.api.thirdauth.util.StringUtil;
import com.sptg.permissions.api.thirdauth.util.XXTeaUtil;
import com.sptg.statistics.api.entity.SysOperationLog;
import com.sptg.statistics.api.feigns.SysOperationLogFeign;
import com.xkcoding.http.util.MapUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.zhyd.oauth.model.AuthCallback;
import me.zhyd.oauth.model.AuthResponse;
import me.zhyd.oauth.model.AuthToken;
import me.zhyd.oauth.model.AuthUser;
import me.zhyd.oauth.request.AuthRequest;
import me.zhyd.oauth.utils.AuthStateUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import static com.sptg.permissions.api.thirdauth.util.AuthRequestUtil.getAuthRequest;

/**
 * title: AuthenticationController
 * package: com.sptg.gateway.controller.permissions
 * description: 用户认证-控制器
 *
 *                  
 *                 
 */
@Slf4j
@RestController
@RequiredArgsConstructor
@RequestMapping(value = "/permissions/third/authentication")
public class ThirdAuthenticationController {

    /* -------------------------------------------------- 接口注入 -------------------------------------------------- */

    private final AccountAuthenticationFeign accountAuthenticationFeign;
    private final SecurityServiceInterface<Account> securityServiceInterface;
    private final SysOperationLogFeign sysOperationLogFeign;
    private final AccountFeign accountFeign;
    private final AccountOauthFeign accountOauthFeign;
    /* --------------------------------------------------- 控制器 --------------------------------------------------- */

    /**
     * 功能描述: 访问授权
     * @return ResultBean
     *                  
     *                       
     */
    @RequestMapping(value = "/render/{source}")
    @ResponseBody
    public void renderAuth(@PathVariable("source") String source, HttpServletResponse response) throws IOException {
        log.warn("进入render：" + source);
        AuthRequest authRequest = getAuthRequest(source);
        String authorizeUrl = authRequest.authorize(AuthStateUtils.createState());
        log.warn(authorizeUrl);
        response.sendRedirect(authorizeUrl);
    }

    /**
     * oauth平台中配置的授权回调地址，以本项目为例，在创建github授权应用时的回调地址应为：http://127.0.0.1:8443/oauth/callback/github
     */
    @RequestMapping("/callback/{source}")
    public ModelAndView login(@PathVariable("source") String source, AuthCallback callback, HttpServletRequest request) {
        AuthRequest authRequest = getAuthRequest(source);
        callback = this.getAuthCallback(source, callback, request);
        AuthResponse<AuthUser> response = authRequest.login(callback);
        log.warn(JSONObject.toJSONString(response));

        if (response.ok()) {
            AuthUser data = response.getData();
            AccountOauthDto accountOauthDto = new AccountOauthDto();
            accountOauthDto.setMobile(data.getUsername());
            accountOauthDto.setUuId(data.getUuid());
            accountOauthDto.setSource(source);
            ResultBean<AccountOauth> dbOauth = this.accountOauthFeign.getByUuIdAndSource(accountOauthDto);
            Account dbAccount = this.accountFeign.getByUserMobile(accountOauthDto.getMobile());
            if(dbOauth.getData() == null){
                if(dbAccount == null){
                    return new ModelAndView("common/guest-error");
                }else{
                    //自动绑定用户账号
                    accountOauthDto.setAccountId(dbAccount.getId());
                    ResultBean<Boolean> resultBean = this.accountOauthFeign.bindUser(accountOauthDto);
                    if(!resultBean.getData()){
                        return new ModelAndView("common/guest-error");
                    }
                }
            }else{
                this.accountOauthFeign.bindUser(accountOauthDto);
            }
            LoginDto loginDto = new LoginDto();
            loginDto.setLoginName(dbAccount.getLoginName());
            ResultBean<Account> resultBean = this.accountAuthenticationFeign.oauthLogin(loginDto);

            //  用户信息
            Account account = resultBean.getData();
            //  创建用户令牌
            String token = this.securityServiceInterface.createUserToken(account);
            //  生成cookie
            CookieUtils.setCookie(HttpConstant.ACCESS_TOKEN,token);
            //  登录日志
            SysOperationLog sysOperationLog = new SysOperationLog(SysLogConstant.LOGIN_EVENT,WebUtils.getIp(),account);
            account.setLastLoginDate(new Date());
            account.setLastLoginIp(WebUtils.getIp());
            accountFeign.updateById(account);
            sysOperationLogFeign.info(sysOperationLog);
            return new ModelAndView("redirect:/");
        }

        Map<String, Object> map = new HashMap<>(1);
        map.put("errorMsg", "登录异常，请重新登录");

        return new ModelAndView("error", map);
    }

    @RequestMapping("/mini/login/{source}")
    public ResultBean miniLogin(@PathVariable("source") String source, @RequestBody Map<String, String> requestMap) {
        AuthToken authToken = null;
        Map<String, Object> errorMap = new HashMap<>(1);
        errorMap.put("errorMsg", "登录异常，请重新登录");
        if("CTWING".equals(source)){
            try {
                // XXTea解密非公共加密参数
                String decValue = new String(XXTeaUtil.decrypt(ByteFormat.hexToBytes(requestMap.get("paras")), CtwingAuthConstants.APP_SECRET.getBytes(CtwingAuthConstants.DEFAULT_CHARSET)));
                Map<String, String> resultMap = MapUtil.parseStringToMap(decValue, false);
                if(0 == Integer.valueOf(resultMap.get("result"))){
                    authToken = new AuthToken();
                    authToken.setAccessToken(resultMap.get("accessToken"));
                    authToken.setUid(resultMap.get("openId"));
                    AuthCtwingRequest authRequest = (AuthCtwingRequest)getAuthRequest(source);
                    AuthUser data = authRequest.getUserInfo(authToken);
                    AccountOauthDto accountOauthDto = new AccountOauthDto();
                    accountOauthDto.setMobile(data.getUsername());
                    accountOauthDto.setUuId(data.getUuid());
                    accountOauthDto.setSource(source);
                    ResultBean<AccountOauth> dbOauth = this.accountOauthFeign.getByUuIdAndSource(accountOauthDto);
                    Account dbAccount = this.accountFeign.getByUserMobile(accountOauthDto.getMobile());
                    if(dbOauth.getData() == null){
                        if(dbAccount == null){
                            return new ResultBean<>(ResultEnum.OAUTH_FAIL);
                        }else{
                            //自动绑定用户账号
                            accountOauthDto.setAccountId(dbAccount.getId());
                            ResultBean<Boolean> resultBean = this.accountOauthFeign.bindUser(accountOauthDto);
                            if(!resultBean.getData()){
                                return new ResultBean<>(ResultEnum.OAUTH_FAIL);
                            }
                        }
                    }else{
                        this.accountOauthFeign.bindUser(accountOauthDto);
                    }
                    LoginDto loginDto = new LoginDto();
                    loginDto.setLoginName(dbAccount.getLoginName());
                    ResultBean<Account> resultBean = this.accountAuthenticationFeign.oauthLogin(loginDto);

                    //  用户信息
                    Account account = resultBean.getData();
                    //  创建用户令牌
                    String token = this.securityServiceInterface.createUserToken(account);
                    //  生成cookie
                    CookieUtils.setCookie(HttpConstant.ACCESS_TOKEN,token);
                    //  登录日志
                    SysOperationLog sysOperationLog = new SysOperationLog(SysLogConstant.LOGIN_EVENT,WebUtils.getIp(),account);
                    account.setLastLoginDate(new Date());
                    account.setLastLoginIp(WebUtils.getIp());
                    accountFeign.updateById(account);
                    sysOperationLogFeign.info(sysOperationLog);
                    return new ResultBean<>(ResultEnum.SUCCESS, token);
                }else{
                    return new ResultBean<>(ResultEnum.OAUTH_FAIL);
                }
            } catch (Exception e) {
                e.printStackTrace();
                return new ResultBean<>(ResultEnum.OAUTH_FAIL);
            }
        }else{
            return new ResultBean<>(ResultEnum.OAUTH_FAIL);
        }
    }

    private AuthCallback getAuthCallback(String source, AuthCallback authCallback, HttpServletRequest request){
        if("CTWING".equals(source)){
            String paras = request.getParameter("paras");
            try {
                // XXTea解密非公共加密参数
                String decValue = new String(XXTeaUtil.decrypt(ByteFormat.hexToBytes(paras), CtwingAuthConstants.APP_SECRET.getBytes(CtwingAuthConstants.DEFAULT_CHARSET)));
                Map<String, String> resultMap = MapUtil.parseStringToMap(decValue, false);
                if(0 == Integer.valueOf(resultMap.get("result"))){
                    authCallback.setCode(resultMap.get("code"));
                    authCallback.setState(resultMap.get("state"));
                }
                log.warn(decValue);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return authCallback;
    }

    private AuthToken decryptParas(String source, String paras) throws Exception{
        AuthToken authToken = null;
        if("CTWING".equals(source)){
            try {
                // XXTea解密非公共加密参数
                String decValue = new String(XXTeaUtil.decrypt(ByteFormat.hexToBytes(paras), CtwingAuthConstants.APP_SECRET.getBytes(CtwingAuthConstants.DEFAULT_CHARSET)));
                Map<String, String> resultMap = MapUtil.parseStringToMap(decValue, false);
                if(0 == Integer.valueOf(resultMap.get("result"))){
                    authToken = new AuthToken();
                    authToken.setAccessToken(resultMap.get("accessToken"));
                    authToken.setUid(resultMap.get("openId"));
                }
                return authToken;
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
        }else{
            throw new Exception("未知解密数据");
        }
    }

    @RequestMapping("/test/bindUser")
    public ModelAndView test(AccountOauthDto accountOauthDto) {
        //{"code":2000,"data":{"avatar":"http://avatar.e.189.cn/avatar/default/default_middle.jpg","email":"","nickname":"","source":"CTWING","token":{"accessToken":"5826e7983c5b423cb8f5ae83975d59bd","expireIn":7716616,"refreshToken":"218418f61c5f4758b75045578f0b3839","refreshTokenExpireIn":0},"username":"15622205184","uuid":"657f5c8dd9b819562fdcc672d218f4d2"}}
        accountOauthDto.setSource("CTWING");
        ResultBean<AccountOauth> dbOauth = this.accountOauthFeign.getByUuIdAndSource(accountOauthDto);
        Account dbAccount = this.accountFeign.getByUserMobile(accountOauthDto.getMobile());
        if(dbOauth.getData() == null){
            if(dbAccount == null){
                return new ModelAndView("common/guest-error");
            }else{
                //自动绑定用户账号
                accountOauthDto.setAccountId(dbAccount.getId());
                ResultBean<Boolean> resultBean = this.accountOauthFeign.bindUser(accountOauthDto);
                if(!resultBean.getData()){
                    return new ModelAndView("common/guest-error");
                }
            }
        }else{
            this.accountOauthFeign.bindUser(accountOauthDto);
        }
        LoginDto loginDto = new LoginDto();
        loginDto.setLoginName(dbAccount.getLoginName());
        ResultBean<Account> resultBean = this.accountAuthenticationFeign.oauthLogin(loginDto);

        //  用户信息
        Account account = resultBean.getData();
        //  创建用户令牌
        String token = this.securityServiceInterface.createUserToken(account);
        //  生成cookie
        CookieUtils.setCookie(HttpConstant.ACCESS_TOKEN,token);
        //  登录日志
        SysOperationLog sysOperationLog = new SysOperationLog(SysLogConstant.LOGIN_EVENT,WebUtils.getIp(),account);
        account.setLastLoginDate(new Date());
        account.setLastLoginIp(WebUtils.getIp());
        accountFeign.updateById(account);
        sysOperationLogFeign.info(sysOperationLog);
        return new ModelAndView("redirect:/");
    }

}
