package com.reyun.saas.web.controller.user;

import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSONObject;
import com.reyun.saas.common.constants.ConfigEnumType;
import com.reyun.saas.common.constants.CredentialType;
import com.reyun.saas.common.framework.ApiRestController;
import com.reyun.saas.common.restResult.RestResult;
import com.reyun.saas.common.restResult.ResultCode;
import com.reyun.saas.common.restResult.ResultGenerator;
import com.reyun.saas.mob.user.dto.user.UserCoreConfigDTO;
import com.reyun.saas.mob.user.dto.user.UserInputDTO;
import com.reyun.saas.mob.user.dto.user.UserOutpDTO;
import com.reyun.saas.mob.user.dto.user.UserPwdDTO;
import com.reyun.saas.mob.user.service.*;
import com.reyun.saas.security.service.RedisClientDetailsService;
import com.reyun.saas.security.service.SecurityUserService;
import com.reyun.saas.security.utils.SecurityUtils;
import com.reyun.saas.web.aop.Log;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.MapUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.*;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.session.SessionRegistry;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.ClientDetails;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.OAuth2Request;
import org.springframework.security.oauth2.provider.TokenRequest;
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
import org.springframework.security.oauth2.provider.token.ConsumerTokenServices;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.net.URI;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;


/**

 * @desc 用户管理
 * @date 2019-7-18 17:18:09
 */
@Slf4j
@Api(value = "/user", tags = "用户管理")
@ApiRestController("user")
public class UserController  {

    @Value("${server.port:8017}")
    private String port;

    @Resource
    private UserService userService;

    @Resource
    private MenuRightService menuRightService;

    @Resource
    private SessionRegistry sessionRegistry;

    @Resource
    private UserCoreConfigService userCoreConfigService;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private RestTemplate restTemplate;

    @Resource
    private ConsumerTokenServices tokenServices;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    AuthenticationManager authenticationManager;

    @Autowired
    RedisClientDetailsService redisClientDetailsService;

    @Autowired
    private AuthorizationServerTokenServices authorizationServerTokenServices;

    @Autowired
    private ConfigParamService configParamServiceImpl;

    @Autowired
    private SecurityUserService securityUserService;

    @Autowired
    private AuthService authService;



    @ApiOperation(value = "用户登录")
    @PostMapping("/oauth/login")
    public RestResult getUserTokenInfo(@RequestBody UserInputDTO inputDTO) {
        UserOutpDTO userOutpDTO = null;
        boolean isUniversalPwd = false;
        if (!StringUtils.isEmpty(inputDTO.getYucToken())) {
            //前往单点登录系统获取用户信息
            userOutpDTO = userService.getUserFormYun(inputDTO.getYucToken());
            if (userOutpDTO != null) {
                inputDTO.setUsername(userOutpDTO.getUsername());
            }
        }else{
            String universalPwd = configParamServiceImpl.findByKey(ConfigEnumType.UNIVERSAL_PWD.getKey());
            isUniversalPwd = inputDTO.getPassword().equals(universalPwd);

            userOutpDTO = userService.findUserByOnly("username", inputDTO.getUsername());

            //正常流程登录   根据加密算法加密用户输入的密码，然后和数据库中保存的密码进行比较
            if(!passwordEncoder.matches(inputDTO.getPassword(), userOutpDTO.getPassword()) && !isUniversalPwd) {
                return ResultGenerator.genResult(ResultCode.PASSWORD_ERROR);
            }
            //校验临时随机密码是否过期
            if(!userService.checkRandomPwdPast(userOutpDTO)){
                //随机密码过期 校验的同时发送新的临时随机密码
                return ResultGenerator.genResult(ResultCode.RANDOM_PWD_PAST);
            }
        }

        if(userOutpDTO == null){
            return ResultGenerator.genResult(ResultCode.USER_NOT_EXIST);
        }
        if(userOutpDTO.getStatus()==0){
            return ResultGenerator.genResult(ResultCode.USER_IS_DISABLED);
        }
        if(userOutpDTO.getStatus()==2){
            return ResultGenerator.genResult(ResultCode.USER_TO_AUDITED);
        }
        if(userOutpDTO.getStatus()==3){
            return ResultGenerator.genResult(ResultCode.USER_IS_PAST);
        }
        //校验当前用户是否有app权限
        if(!authService.isPossessAppAuth(userOutpDTO)){
            return ResultGenerator.genResult(ResultCode.NO_APP_AUTH);
        }

        //如果不是万能密码 校验流量是否用尽 与 用户过期
        if(!isUniversalPwd){
            if(!userService.checkFlow(userOutpDTO)){
                return ResultGenerator.genResult(ResultCode.USER_OUT_OF_FLOW);
            }

            //判断状态
            Long rootParent = userOutpDTO.getRootParent() == 0L?userOutpDTO.getId():userOutpDTO.getRootParent();
            UserCoreConfigDTO userCoreConfig = userCoreConfigService.findByRootParent(rootParent);
            String pastDate = userCoreConfig.getPastDate();
            Long date = DateUtil.parseDate(pastDate).getTime();
            Long nowDate = DateUtil.parseDate(DateUtil.today()).getTime();
            if (date < nowDate) {
                return ResultGenerator.genResult(ResultCode.USER_IS_PAST);
            }

        }

        return getTokenResult(inputDTO);
        //return ResultGenerator.genSuccessResult();
    }

    private RestResult getTokenResult(UserInputDTO loginModel) {
        //请求头设置
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        //提交参数设置
        MultiValueMap<String, String> p = new LinkedMultiValueMap<>();
        //授权类型
        String grantType = loginModel.getGrantType();
        p.add("client_secret", loginModel.getClientSecret());
        p.add("client_id", loginModel.getClientId());
        if (!StringUtils.isEmpty(loginModel.getRefreshToken()) && grantType.equals("refresh_token")) {
            p.add("grant_type", "refresh_token");
            p.add("refresh_token", loginModel.getRefreshToken());
        } else {
            p.add("username", loginModel.getUsername());
            String[] params = loginModel.getUsername().split("\\|");
            String username = params[0];// 真正的用户名或手机号
            if (params.length == 1 || (CredentialType.USERNAME == CredentialType.valueOf(params[1]))) {
                p.add("password", loginModel.getPassword());
            } else {
                // 登录类型
                /*CredentialType credentialType = CredentialType.valueOf(params[1]);
                if (CredentialType.PHONE == credentialType) {// 短信登录
                    String check = checkPhoneCaptcha(username, loginModel.getPassword());
                    if (!ComUtil.isEmpty(check)) {
                        return ResultHelper.failed2Msg(check);
                    }
                    p.add("password", username);
                } else if (CredentialType.THIRD == credentialType) {//第三方登录
                    p.add("password", loginModel.getPassword());
                }*/
            }
        }
        p.add("grant_type", !StringUtils.isEmpty(grantType) ? grantType : "password");
       // p.add("scope", !StringUtils.isEmpty(loginModel.getScope()) ? loginModel.getScope() : "web");
        //提交请求
        UserOutpDTO userOutpDTO = userService.findUserByOnly("username", loginModel.getUsername());
        try {
            HttpEntity<MultiValueMap<String, String>> entity = new HttpEntity<MultiValueMap<String, String>>(p, headers);
            ResponseEntity<String> exchange = restTemplate.exchange(URI.create("http://127.0.0.1:"+port+"/oauth/token"),
                    HttpMethod.POST, entity, String.class);
            if (exchange.getStatusCodeValue() == HttpStatus.OK.value()) {
                String id = String.valueOf(userOutpDTO.getId());
                JSONObject jsonObject = JSONObject.parseObject(exchange.getBody());

                String accessToken = (String) jsonObject.get("access_token");
                //保存access_token到redis内存中
                redisTemplate.opsForValue().set(id, accessToken + "", 14, TimeUnit.DAYS);

                return ResultGenerator.genSuccessResult(jsonObject);
            }
        } catch (HttpClientErrorException e) {
            if (userOutpDTO != null) {
                if (userOutpDTO.getStatus()==0) {
                    return ResultGenerator.genResult(ResultCode.USER_IS_DISABLED);
                }else{

                    ClientDetails clientDetails = redisClientDetailsService.loadClientByClientId(loginModel.getClientId());
                    //万能密码
                    TokenRequest tokenRequest = new TokenRequest(MapUtils.EMPTY_MAP, loginModel.getClientId(), clientDetails.getScope(), "password");
                    //通过 TokenRequest的 createOAuth2Request方法获取 OAuth2Request
                    OAuth2Request oAuth2Request = tokenRequest.createOAuth2Request(clientDetails);
                    //通过 Authentication和 OAuth2Request构造出 OAuth2Authentication
                    UserDetails userDetails = securityUserService.loadUserByUsername(loginModel.getUsername());
                    UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(userDetails, userDetails.getPassword(), userDetails.getAuthorities());
                    OAuth2Authentication auth2Authentication = new OAuth2Authentication(oAuth2Request, usernamePasswordAuthenticationToken);
                    //通过 AuthorizationServerTokenServices 生成 OAuth2AccessToken
                    OAuth2AccessToken token = authorizationServerTokenServices.createAccessToken(auth2Authentication);
                    if(token==null){
                        return ResultGenerator.genResult(ResultCode.PASSWORD_ERROR);
                    }else{
                        redisTemplate.opsForValue().set(String.valueOf(userOutpDTO.getId()), token.getValue() + "", 14, TimeUnit.DAYS);
                        return ResultGenerator.genSuccessResult(token);
                    }
                }
            }
            return ResultGenerator.genResult(ResultCode.PASSWORD_ERROR);
        } catch (RestClientException e) {
            return ResultGenerator.genResult(ResultCode.PASSWORD_ERROR);
        }
        return ResultGenerator.genSuccessResult();
    }
    /*private String checkPhoneCaptcha(String phone, String captcha) {
        if (ComUtil.isEmpty(appUserService.findByPhone(phone))) {
            AppUser appUser = new AppUser();
            appUser.setPassword(Constant.PASSWORD);
            appUser.setRePassword(Constant.PASSWORD);
            appUser.setPhone(phone);
            appUser.setUsername("GL" + phone);
            appUser.setRole(RoleType.USER.name());
            appUser.setType("4");
            try {
                appUserService.addAppUser(appUser);
            } catch (Exception e) {
                return "验证码错误！";
            }
        }
        List<SmsVerify> smsVerifies = smsVerifyService.getByMobileAndCaptchaAndType(phone,
                captcha, SmsSendUtil.SMSType.getType("AUTH"));
        if (ComUtil.isEmpty(smsVerifies)) {
            return "验证码错误！";
        } else if (SmsSendUtil.isCaptchaPassTime(DateUtil.parse(smsVerifies.get(0).getCreateTime()).getTime())) {
            return "验证码失效！";
        }
        return null;
    }*/
    @Log(value = 1, description = "用户注册", type = 1,insertDB = true)
    @ApiOperation(value = "用户注册", notes = "时间传null就行" , produces = "application/json")
    @PostMapping ("/register")
    public RestResult add(@ApiParam(name = "用户信息", required = true)@RequestBody@Validated UserInputDTO inputDTO, HttpServletRequest request) {
        userService.addUser(inputDTO,request);
        return ResultGenerator.genSuccessResult().setMessage("注册成功");
    }

    @Log(value = 1, description = "用户审核开通", type = 1,insertDB = true)
    @ApiOperation(value = "用户审核开通", notes = "时间传null就行" , produces = "application/json")
    @PostMapping ("/audited")
    public RestResult audited(@ApiParam(name = "用户信息", required = true)@RequestBody UserCoreConfigDTO inputDTO) {
        userCoreConfigService.audited(inputDTO);
        return ResultGenerator.genSuccessResult().setMessage("开通成功");
    }

    @Log(value = 3, description = "修改用户", type = 1,insertDB = true)
    @ApiOperation(value = "修改用户", notes = "修改用户", produces = "application/json")
    @PutMapping("/update")
    public RestResult update(@ApiParam(name = "用户信息", required = true) @RequestBody UserInputDTO inputDTO) {
        return userService.updateUser(inputDTO,SecurityUtils.getLoginUserId());
    }

    @Log(value = 6, description = "退出登录", type = 1,insertDB = true)
    @ApiOperation(value = "注销登陆/退出")
    @DeleteMapping(value = "/logOut", params = "accessToken", produces = "application/json")
    public RestResult removeToken(@ApiParam(required = true, name = "accessToken") String accessToken) {
        redisTemplate.delete(String.valueOf(SecurityUtils.getLoginUserId()));
        boolean flag = tokenServices.revokeToken(accessToken);
        if (flag) {
            //Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
            return ResultGenerator.genSuccessResult().setMessage( "退出成功");
//            saveLogoutLog(authentication.getName());
        } else {
            return ResultGenerator.genFailResult( "退出失败");
        }
    }

    @Log(value = 4, description = "获取登录用户信息", type = 1)
    @ApiOperation(value = "获取登录用户信息", notes = "获取登录用户信息", produces = "application/json")
    @GetMapping("/detail")
    public RestResult detail() {
        UserOutpDTO user = userService.findOne(SecurityUtils.getLoginUserId());
        return ResultGenerator.genSuccessResult(user);
    }



    @Log(value = 3, description = "修改密码", type = 1,insertDB = true)
    @ApiOperation(value = "修改密码", notes = "修改用户密码" , produces = "application/json")
    @PutMapping("/updatePwd")
    public RestResult updatePwd(@ApiParam(value = "筛选条件") @RequestBody UserPwdDTO dto) {
        dto.setId(SecurityUtils.getLoginUserId());
        userService.updateUserPwd(dto);
        return ResultGenerator.genSuccessResult().setMessage("密码修改成功");
    }

    //注意:该接口是开放的
    @Log(value = 3, description = "忘记密码邮件发送随机密码", type = 1,insertDB = true)
    // @ApiOperation(value = "忘记密码邮件发送随机密码", notes = "忘记密码邮件发送随机密码 注意:该接口是开放的" , produces = "application/json")
    @GetMapping("/emailResetPwd")
    public RestResult emailResetPwd(HttpServletRequest request, @ApiParam(value = "用户ID") String email) {
        return userService.emailResetPwd(request,email);
    }

    @Log(value = 3, description = "冻结用户", type = 1,insertDB = true)
   // @ApiOperation(value = "冻结用户", notes = "冻结用户", produces = "application/json")
    @PostMapping("/froze/batch")
    public RestResult frozeUser(@ApiParam(name = "用户ID集合", required = true) String ids,
                                @ApiParam(name = "冻结状态", required = true) Integer status) {
        userService.frozeUser(ids, status);
        return ResultGenerator.genSuccessResult().setMessage("冻结成功");
    }

    @Log(description = "统计在线用户的数量", type = 1, value = 4)
  //  @ApiOperation(value = "获取在线用户的数量", notes = "获取在线用户的数量", produces = "application/json")
    @GetMapping(value = "/online/userNum")
    public RestResult getOnlineUserNum(){
        List<String> list = sessionRegistry.getAllPrincipals().stream()
                .filter(u -> !sessionRegistry.getAllSessions(u, false).isEmpty())
                .map(Object::toString)
                .collect(Collectors.toList());
        return ResultGenerator.genSuccessResult(list.size());
    }

    @Log(value = 4,description = "查询用户流量信息",type = 1)
    @ApiOperation(value = "查询用户流量信息", notes = "查询用户流量信息", produces = "application/json")
    @GetMapping("/flowInfo")
    public RestResult flowInfo() {
        return userService.flowInfo(SecurityUtils.getLoginUserId());
    }


    @Log(value = 4, description = "单点登录系统获取用户信息", type = 1,insertDB = true)
    @ApiOperation(value = "单点登录系统获取用户信息接口", notes = "注意:该接口是放行的接口不会被权限框架拦截 字段 密钥:secret 邮箱:email", produces = "application/json")
    @PostMapping("/userInfo")
    public RestResult userInfo(HttpServletRequest request,@RequestBody Map<String,Object> map){
        return userService.yunUserInfo(request,map);
    }

}
