package com.lightinit.hsdataportal.controller.open;
import com.google.code.kaptcha.Constants;
import com.lightinit.hsdataportal.common.*;
import com.lightinit.hsdataportal.controller.BaseController;
import com.lightinit.hsdataportal.dictionary.DicCodeType;
import com.lightinit.hsdataportal.entity.UserSecurityCode;
import com.lightinit.hsdataportal.entity.UserSecurityCodeExample;
import com.lightinit.hsdataportal.model.LoginUser;
import com.lightinit.hsdataportal.model.ResultState;
import com.lightinit.hsdataportal.model.ResultStateCode;
import com.lightinit.hsdataportal.model.ShareRegisterModel;
import com.lightinit.hsdataportal.service.IUserService;
import com.lightinit.hsdataportal.service.open.IAccountService;
import com.lightinit.hsdataportal.spring.UsernamePasswordUserTypeToken;
import net.sf.json.JSONObject;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.util.SavedRequest;
import org.apache.shiro.web.util.WebUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.view.InternalResourceViewResolver;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * Created by WangYao on 2018/6/7.
 */
@Controller
@RequestMapping(value = "/open/account")
public class AccountController extends BaseController {

    @Value("${msgs.server.url}")
    private String msgsServer;

    @Value("${devops.server.url}")
    private String devopsServer;

    @Autowired
    private IAccountService accountService;
    @Autowired
    private IUserService userService;

    @RequestMapping(value = "login.htm")
    public String login(ModelMap model, HttpServletRequest request) {
        return "open/account/login";
    }

    @RequestMapping(value = "login.action")
    public String doLogin(Model model, HttpSession session, HttpServletRequest request, @RequestParam String username, @RequestParam String password, @RequestParam String captcha) {
        ResultState resultState = new ResultState();
        model.addAttribute("resultState", resultState);
        String capText=session.getAttribute(Constants.KAPTCHA_SESSION_KEY)!=null?session.getAttribute(Constants.KAPTCHA_SESSION_KEY).toString():"";
        if(StringUtils.isEmpty(capText) || StringUtils.isEmpty(captcha)){
            resultState.setStateCode(ResultStateCode.INVALID_DATA);
            resultState.setMsg("验证码不能为空");
            return "open/account/login";
        }else if (capText.equalsIgnoreCase(captcha)==false){
            resultState.setStateCode(ResultStateCode.INVALID_DATA);
            resultState.setMsg("验证码不正确");
            return "open/account/login";
        }
        if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password)){
            resultState.setStateCode(ResultStateCode.INVALID_DATA);
            resultState.setMsg("用户名和密码不能为空");
            return "open/account/login";
        }
        UsernamePasswordUserTypeToken token = new UsernamePasswordUserTypeToken(username, password, "user");
        Subject currentUser = SecurityUtils.getSubject();
        //token.setRememberMe(true);
        try {
            //在调用了login方法后,SecurityManager会收到AuthenticationToken,并将其发送给已配置的Realm执行必须的认证检查
            currentUser.login(token);
            if (currentUser.isAuthenticated()) {
                session.setAttribute("userinfo", username);
                session.setAttribute(LoginUser.SESSION_KEY_LOGIN_USER, accountService.getLoginUserByUsername(username));
            } else {
                token.clear();
            }
        } catch (UnknownAccountException uae) {
            resultState.setStateCode(ResultStateCode.INVALID_DATA);
            resultState.setMsg("用户名不存在");
            token.clear();
        } catch (IncorrectCredentialsException ice) {
            resultState.setStateCode(ResultStateCode.INVALID_DATA);
            resultState.setMsg("用户名或密码错误");
            token.clear();
        } catch (LockedAccountException lae) {
            resultState.setStateCode(ResultStateCode.INVALID_DATA);
            resultState.setMsg("用户被锁定");
            token.clear();
        } catch (ExcessiveAttemptsException eae) {
            resultState.setStateCode(ResultStateCode.INVALID_DATA);
            resultState.setMsg("尝试次数过多");
            token.clear();
        } catch (AuthenticationException ae) {
            //通过处理Shiro的运行时AuthenticationException就可以控制用户登录失败或密码错误时的情景
            resultState.setStateCode(ResultStateCode.INVALID_DATA);
            resultState.setMsg("用户名或密码错误");
        }

        if (resultState.getStateCode() == ResultStateCode.SUCCESS){
            SavedRequest savedRequest = WebUtils.getSavedRequest(request);
            if (savedRequest != null){
                String returnUrl = WebUtils.getSavedRequest(request).getRequestUrl();
                if (StringUtils.isNotEmpty(returnUrl)){
                    return InternalResourceViewResolver.REDIRECT_URL_PREFIX + returnUrl;
                }
            }
            return InternalResourceViewResolver.REDIRECT_URL_PREFIX + "/";
        }
        return "open/account/login";
    }

    @RequestMapping(value = "logout.action")
    public String logout(ModelMap model, HttpSession session){
        Subject currentUser = SecurityUtils.getSubject();
        try {
            currentUser.logout();
            session.invalidate();
        } catch (Exception e) {
        }
        return InternalResourceViewResolver.REDIRECT_URL_PREFIX + "/";
    }

    @RequestMapping(value = "register.htm")
    public String register(ModelMap model, HttpServletRequest request) {
        return "open/account/register";
    }


    @RequestMapping(value = "register.action")
    @ResponseBody
    public ResultState register(ShareRegisterModel shareRegisterModel){
        if (StringUtils.isEmpty(shareRegisterModel.getUsername()) || StringUtils.isEmpty(shareRegisterModel.getPassword()) || StringUtils.isEmpty(shareRegisterModel.getPassword1())){
            return buildInvalidResultState("用户名、密码不能为空");
        }
        if(!shareRegisterModel.getUsername().matches("^[a-z0-9]+$")){
            return buildInvalidResultState("用户名只能由小写字母和数字组成");
        }
        if(shareRegisterModel.getUsername().length()>30){
            return buildInvalidResultState("用户名最大长度30个字母");
        }
        ResultState resultState = accountService.register(shareRegisterModel);
        if(resultState.getStateCode()!=200){
            return resultState;
        }

        //同步服务开发环境和微服务管控平台
        ExecutorService executorService = Executors.newCachedThreadPool();
        executorService.execute(new Runnable() {
            @Override
            public void run() {
                //1.----->同步到管控平台
                //获取token
                String token = TokenUtils.getToken();
                //请求头
                if(token!=null){
                    HashMap<String, String> authheaderMap = new HashMap<>();
                    authheaderMap.put("content-type","application/json");
                    authheaderMap.put("Authorization","Bearer "+token);
                    String passMessage = HttpUtil.httpPost(msgsServer + TokenUtils.MsgsServer.USERPATH, authheaderMap, JSONObject.fromObject(shareRegisterModel).toString());
                }

                //2.------>同步到服务开发环境平台
                //为服务开发环境平台同步添加必要属性
                JSONObject group = JSONObject.fromObject(new Object());
                group.accumulate("groupName","group-"+shareRegisterModel.getUsername());
                group.accumulate("groupDesc","desc-"+shareRegisterModel.getUsername());
                group.accumulate("gitLabId",1);
                group.accumulate("jenkinsId",1);
                group.accumulate("harborId",1);
                group.accumulate("managerId",0);
                group.accumulate("status",1);
                //新建租户并获取id
                //json请求头
                HashMap<String, String> jsonHeaderMap = new HashMap<>();
                jsonHeaderMap.put("content-type","application/json");
                String  message= HttpUtil.httpPost(devopsServer+TokenUtils.DevopsServer.GROUPPATH, jsonHeaderMap, group.toString());
                //从返回的message中获取需要的id
                JSONObject groupJson = JSONObject.fromObject(message);
                if(groupJson.get("message")!=null && StringUtils.isNotEmpty(groupJson.get("message").toString()) && "success".equals(groupJson.get("message").toString()) ){
                    long id = Long.parseLong(JSONObject.fromObject(groupJson.get("data")).get("id").toString());
                    //为开发平台同步添加必要的属性
                    JSONObject user = JSONObject.fromObject(new Object());
                    user.accumulate("userCode",shareRegisterModel.getUsername());
                    user.accumulate("userName",shareRegisterModel.getUsername());
                    String encrypt=null;
                    try{
                        RSAUtils.loadKeyPair();
                        encrypt= RSAUtils.encrypt("testone1");//固定不变。鬼知道为啥，不然同步不过去
                    }catch(Exception e){
                        e.printStackTrace();
                    }
                    user.accumulate("userPass",encrypt);
                    user.accumulate("groupId",id);
                    user.accumulate("isValid",1);
                    HashMap<String, String> map = new HashMap<>();
                    map.put("content-type","application/json");
                    String  userMessage= HttpUtil.httpPost(devopsServer+TokenUtils.DevopsServer.USERPATH,jsonHeaderMap,user.toString());
                    //将pass平台注册的用户id和本地用户id插入到userAuthSetting表中
                    JSONObject userJson = JSONObject.fromObject(userMessage);
                    if(userJson.get("message")!=null && StringUtils.isNotEmpty(userJson.get("message").toString()) && "success".equals(userJson.get("message").toString())){
                        Long passUserId  = Long.parseLong(JSONObject.fromObject(userJson.get("data")).get("id").toString());
                        ResultState rs = accountService.insertUserAuthSetting(Long.parseLong(resultState.getData().toString()), passUserId);
                    }else{
                        ResultState rs = accountService.insertUserAuthSetting(Long.parseLong(resultState.getData().toString()), null);
                    }
                }else{
                    ResultState rs = accountService.insertUserAuthSetting(Long.parseLong(resultState.getData().toString()), null);
                }
                executorService.shutdownNow();
            }
        });
        return resultState ;
    }

    /**
     * @return 验证码
     */
    @RequestMapping(value = "validatePhone.action")
    @ResponseBody
    public ResultState validatePhone(String phone) {
        return  accountService.validatePhone(phone);
    }

    /**
     * @return 判断验证码是否正确
     */
    @RequestMapping(value = "isCode.action")
    @ResponseBody
    public ResultState isCode(String phone,String code) {
        return  accountService.isCode(phone,code);
    }

    /**
     * @return 判断是否显示
     */
    @RequestMapping(value = "isSecurityCode.action")
    @ResponseBody
    public boolean isSecurityCode() {
        return  accountService.isSecurityCode();
    }

    /*
    *@Description 忘记密码首页
    *@Param
    *@Date 2019/4/8
    *@return
    **/
    @RequestMapping(value= "forgetPassword.htm")
    public ModelAndView forgetPasswordIndex(){
        ModelAndView modelAndView =new ModelAndView("open/account/forgetPassword");
        return modelAndView;
    }

    /*
    *@Description 忘记密码
    *@Param
    *@Date 2019/4/8
    *@return
    **/
    @RequestMapping(value= "forgetPassword.action")
    @ResponseBody
    public ResultState forgetPassword( HttpSession session, HttpServletRequest request, @RequestParam String username, @RequestParam String password1,@RequestParam String password2, @RequestParam String captcha,@RequestParam String code){
        LinkedHashMap<Object, Object> errorMap = new LinkedHashMap<>();
        ResultState resultState = new ResultState();
        String capText=session.getAttribute(Constants.KAPTCHA_SESSION_KEY)!=null?session.getAttribute(Constants.KAPTCHA_SESSION_KEY).toString():"";
        if(StringUtils.isEmpty(capText) || StringUtils.isEmpty(captcha)) {
            errorMap.put("captcha","验证码不能为空");
            return buildInvalidResultState("",errorMap);
        }else if(!capText.equals(captcha)){
            errorMap.put("captcha","验证码不正确");
            return buildInvalidResultState("",errorMap);
        }else if(StringUtils.isEmpty(code) || !code.equals(session.getAttribute("code"))){
            errorMap.put("code","手机验证码不正确");
            return buildInvalidResultState("",errorMap);
        }else if(((Long)session.getAttribute("codeExpire")+1000*60*5) > new Date().getTime()){
            errorMap.put("code","手机验证码过期");
            return buildInvalidResultState("",errorMap);
        }else if(StringUtils.isEmpty(username)){
            errorMap.put("username","用户名不能为空");
            return buildInvalidResultState("",errorMap);
        } else if(StringUtils.isEmpty(password1) || StringUtils.isEmpty(password2)){
            errorMap.put("password1","密码不能为空");
            return buildInvalidResultState("",errorMap);
        }else if(password1.length()>9){
            errorMap.put("password1","密码长度不能超过9位");
            return buildInvalidResultState("",errorMap);
        }else if(!password1.equals(password2)){
            errorMap.put("password2","两次密码不相同");
            return buildInvalidResultState("",errorMap);
        }
        session.removeAttribute("codeExpire");
        session.removeAttribute("code");
        //修改密码
        resultState=userService.forgetPassword(username,password1);
        if(resultState.getStateCode()!=200){
            resultState.setMsg("修改密码失败");
            return resultState;
        }
        resultState.setStateCode(ResultStateCode.SUCCESS);
        resultState.setMsg("修改密码成功");
        return resultState;
    }

    /*
     *@Description 忘记密码--发送到注册手机“验证码“
     *@Param
     *@Date 2019/4/8
     *@return
     **/
    @RequestMapping(value= "getForgetPasswordCode.action")
    @ResponseBody
    public ResultState getForgetPasswordCode(String username,String captcha,HttpSession session){
        String capText=session.getAttribute(Constants.KAPTCHA_SESSION_KEY)!=null?session.getAttribute(Constants.KAPTCHA_SESSION_KEY).toString():"";
        ResultState resultState = new ResultState();
        String phone=userService.getForgetPasswordCode(username);
        if(StringUtils.isEmpty(phone)){
            resultState.setStateCode(ResultStateCode.INVALID_DATA);
            resultState.setMsg("用户名不存在，请先注册");
            return resultState;
        } else if(StringUtils.isEmpty(capText) || StringUtils.isEmpty(captcha) || !capText.equals(captcha)) {
            resultState.setStateCode(ResultStateCode.INVALID_DATA);
            resultState.setMsg("验证码不正确，请重新输入");
            return resultState;
        }
        //发送短信到手机
        Map<String, Object> map = PhoneSendUtils.send(phone);
        if (map!=null){
            if (map.get("Message").equals("OK")&&map.get("Code").equals("OK")){
                String code = (String) map.get("returnCode") ;
                session.setAttribute("code",code);
                session.setAttribute("codeExpire",new Date().getTime());
            }else {
                resultState.setStateCode(ResultStateCode.UNAUTHORIZED);
                resultState.setMsg("获取短信验证码异常！");
                return resultState;
            }
        }else {
            resultState.setStateCode(ResultStateCode.UNAUTHORIZED);
            resultState.setMsg("获取短信验证码异常！");
            return resultState;
        }
        resultState.setMsg("验证码发送到注册手机号中，请查收");
        return resultState;
    }
}
