package com.winsun.item.modular.system.controller;

import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.winsun.auth.core.annotion.Permission;
import com.winsun.auth.core.base.controller.BaseController;
import com.winsun.auth.core.common.model.ResponseData;
import com.winsun.auth.core.util.DateUtil;
import com.winsun.auth.core.util.MD5Util;
import com.winsun.auth.model.user.User;
import com.winsun.auth.model.user.UserUpdatePwd;
import com.winsun.bean.HhrUser;
import com.winsun.bean.SysUser;
import com.winsun.item.core.shiro.ShiroKit;
import com.winsun.item.core.util.AccLoginUtil;
import com.winsun.item.core.util.ResponseEntity;
import com.winsun.item.modular.system.service.IUserService;
import com.winsun.item.util.LoginUtils;
import com.winsun.mapper.HhrUserMapper;
import com.winsun.mapper.SysUserMapper;
import com.winsun.smsUtils.HttpUtil;
import com.winsun.smsUtils.SendSmsAndMail;
import com.winsun.utils.HttpHelper;
import com.winsun.utils.MyBatisPlusUpdateUtils;
import com.winsun.utils.PicturesUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.ui.Model;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URLEncoder;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @Author: chancy
 * @Date: 2020/3/27 16:14
 */
@Slf4j
@RequestMapping("/forgerpw")
@RestController
public class LoginPwdController extends BaseController {

    private static SysUserMapper sysUserMapper;

    private static IUserService userService;

    private static StringRedisTemplate stringRedisTemplate;

    private static HhrUserMapper hhrUserMapper;

    private static String CODE = "verificationCode";

    private static String ERRCODENAME = "ForgeERRCODENAME";

    private static long CODETIME = 1000 * 60 * 5;

    private static int ERRACCOUNT = 10;

    private static String APPID = "wxfc18f5186b729d15";
    private static String APPSECRET = "122278f3fb555468848ff040620505ad";
    //登录验证码标识
    private static String GETPHONECODE = "getPhoneCode";

    @Autowired
    public LoginPwdController(SysUserMapper sysUserMapper, IUserService userService, StringRedisTemplate stringRedisTemplate, HhrUserMapper hhrUserMapper) {
        LoginPwdController.sysUserMapper = sysUserMapper;
        LoginPwdController.userService = userService;
        LoginPwdController.hhrUserMapper = hhrUserMapper;
        LoginPwdController.stringRedisTemplate = stringRedisTemplate;
    }

    /**
     * 微信授权
     *
     * @param request
     * @param response
     * @throws UnsupportedEncodingException
     */
    @RequestMapping(value = "/weixinAuthorization")
    public void weixinAuthorization(HttpServletRequest request, HttpServletResponse response, String state) throws UnsupportedEncodingException {
        String url = "https://open.weixin.qq.com/connect/oauth2/authorize?";
        url += "appid=";
        url += APPID;
        url += "&redirect_uri=" + URLEncoder.encode("http://167460x6b0.51mypc.cn/login", "UTF-8");//此处和微信会调用的域名相同
        url += "&response_type=code&scope=snsapi_userinfo";
        url += "&state=" + state + "#wechat_redirect";
        try {
            response.sendRedirect(url);
        } catch (IOException e) {
            log.error("微信授权异常", e.getMessage());
        }
    }

    /**
     * 测试时使用
     *
     * @param request
     * @param response
     * @throws UnsupportedEncodingException
     */
    @RequestMapping(value = "/weixinAuthorizati")
    public void weixinAuthorization(HttpServletRequest request, HttpServletResponse response) throws UnsupportedEncodingException {
        String url = "https://open.weixin.qq.com/connect/oauth2/authorize?";
        url += "appid=";
        url += APPID;
        url += "&redirect_uri=" + URLEncoder.encode("http://167460x6b0.51mypc.cn/ciop/forgerpw/callBackLogin", "UTF-8");//此处和微信会调用的域名相同
        url += "&response_type=code&scope=snsapi_userinfo";
        url += "&state=#wechat_redirect";
        try {
            response.sendRedirect(url);
        } catch (IOException e) {
            log.error("微信授权异常", e.getMessage());
        }
    }

    @RequestMapping(value = "/callBackLogin")
    public void callBackLogin(HttpServletRequest request, HttpServletResponse response) throws Exception {
        String code = request.getParameter("code");
        String state = request.getParameter("state");
        log.info("code=" + code);
        log.info("state=" + state);
    }

    /**
     * 微信登录
     *
     * @param code
     * @return
     */
    @RequestMapping(value = "/weixinLogin")
    public ResponseData<Map<String, Object>> weixinLogin(String code) {
        if (StringUtils.isBlank(code)) {
            return ResponseData.error("微信授权失效，请重新授权！");
        }
        String url = "https://api.weixin.qq.com/sns/oauth2/access_token?";
        url += "appid=";
        url += APPID;
        url += "&secret=";
        url += APPSECRET;
        url += "&code=" + code + "&grant_type=authorization_code";
        JSONObject jsonObject = null;
        try {
            jsonObject = HttpHelper.doGet(url);
        } catch (Exception e) {
            log.error("微信登录获取用户信息失败", e.getMessage());
        }
        if (jsonObject == null) {
            return ResponseData.error("微信授权失效，请重新授权！");
        }
        String openId = jsonObject.getString("openid");
        Wrapper<HhrUser> wrapper = new EntityWrapper<>();
        wrapper.eq("open_id", openId);
        List<HhrUser> hhrUsers = hhrUserMapper.selectList(wrapper);
        if (hhrUsers.size() == 0) {
            return ResponseData.error("当前微信未绑定账号，请先绑定账号！");
        }
        HhrUser hhrUser = hhrUsers.get(0);
        SysUser sysUser = sysUserMapper.selectById(hhrUser.getId());
        if (StringUtils.isBlank(sysUser.getAccount())) {
            return ResponseData.error("当前账号异常！");
        }
        Map<String, Object> hashMap = new HashMap<>();
        hashMap.put("username", sysUser.getAccount());
        hashMap.put("openId", openId);
        return ResponseData.success(hashMap);
    }

    /**
     * 微信解绑
     *
     * @param code
     * @param username
     * @param verificationCode
     * @return
     */
    @RequestMapping(value = "/weixinUnbundling")
    public ResponseData<String> weixinUnbundling(String code, String username, String verificationCode) {
        if (StringUtils.isBlank(code) || StringUtils.isBlank(username) || StringUtils.isBlank(verificationCode)) {
            return ResponseData.error("解绑失败！");
        }
        String str = stringRedisTemplate.opsForValue().get(username + GETPHONECODE);
        if (StringUtils.isBlank(str)) {
            return ResponseData.error("验证码已失效！");
        }
        if (!str.equals(verificationCode)) {
            return ResponseData.error("验证码错误！");
        }
        Wrapper<SysUser> wrapperU = new EntityWrapper<>();
        wrapperU.eq("account", username);
        List<SysUser> users = sysUserMapper.selectList(wrapperU);
        if (users.size() == 0) {
            return ResponseData.error("当前账号不存在！");
        }
        String url = "https://api.weixin.qq.com/sns/oauth2/access_token?";
        url += "appid=";
        url += APPID;
        url += "&secret=";
        url += APPSECRET;
        url += "&code=" + code + "&grant_type=authorization_code";
        JSONObject jsonObject = null;
        try {
            jsonObject = HttpHelper.doGet(url);
        } catch (Exception e) {
            log.error("微信登录获取用户信息失败", e.getMessage());
        }
        if (jsonObject == null) {
            return ResponseData.error("微信授权失效，请重新授权！");
        }
        String openId = jsonObject.getString("openid");
        SysUser sysUser = users.get(0);
        Wrapper<HhrUser> wrapper = new EntityWrapper<>();
        wrapper.eq("id", sysUser.getId());
        wrapper.eq("open_id", openId);
        List<HhrUser> hhrUsers = hhrUserMapper.selectList(wrapper);
        if (hhrUsers.size() == 0) {
            return ResponseData.error("当前微信和当前账号不匹配！");
        }
        Map<String, Object> dataMapping = new HashMap<>();
        dataMapping.put("open_id", null);
        Integer integer = hhrUserMapper.updateForSet(MyBatisPlusUpdateUtils.toUpdateSet(dataMapping), wrapper);
        if (integer == 1) {
            return ResponseData.success("解绑成功！");
        }
        return ResponseData.error("绑定失败！");
    }

    /**
     * 绑定微信
     *
     * @param code
     * @param username
     * @return
     */
    @RequestMapping("bindingAccount")
    public ResponseData<String> bindingAccount(String code, String username, String verificationCode) {
        if (StringUtils.isBlank(code) || StringUtils.isBlank(username) || StringUtils.isBlank(verificationCode)) {
            return ResponseData.error("绑定失败！");
        }
        String str = stringRedisTemplate.opsForValue().get(username + GETPHONECODE);
        if (StringUtils.isBlank(str)) {
            return ResponseData.error("验证码已失效！");
        }
        if (!str.equals(verificationCode)) {
            return ResponseData.error("验证码错误！");
        }
        Wrapper<SysUser> wrapperU = new EntityWrapper<>();
        wrapperU.eq("account", username);
        List<SysUser> users = sysUserMapper.selectList(wrapperU);
        if (users.size() == 0) {
            return ResponseData.error("当前账号有误！");
        }
        String url = "https://api.weixin.qq.com/sns/oauth2/access_token?";
        url += "appid=";
        url += APPID;
        url += "&secret=";
        url += APPSECRET;
        url += "&code=" + code + "&grant_type=authorization_code";
        JSONObject jsonObject = null;
        try {
            jsonObject = HttpHelper.doGet(url);
        } catch (Exception e) {
            log.error("微信登录获取用户信息失败", e.getMessage());
        }
        if (jsonObject == null) {
            return ResponseData.error("微信授权失效，请重新授权！");
        }
        String openId = jsonObject.getString("openid");

        SysUser sysUser = users.get(0);
        Wrapper wrapper = new EntityWrapper<>();
        wrapper.eq("id", sysUser.getId());
        Map<String, Object> dataMapping = new HashMap<>();
        dataMapping.put("open_id", openId);
        Integer integer = hhrUserMapper.updateForSet(MyBatisPlusUpdateUtils.toUpdateSet(dataMapping), wrapper);
        if (integer == 1) {
            return ResponseData.success(openId);
        }
        return ResponseData.error("绑定失败！");
    }

    /**
     * 忘记密码发送验证码
     *
     * @param username
     * @param
     * @return
     */
    @RequestMapping(value = "verificationCode", method = RequestMethod.POST)
    public Object phoneLoginCode(@RequestParam("username") String username) {
        EntityWrapper<User> userwrapper = new EntityWrapper<>();
        userwrapper.eq("account", username);
        List<User> users = userService.selectList(userwrapper);
        if (CollectionUtils.isEmpty(users)) {
            return ResponseEntity.newJSON("code", 400, "message", "密码或者账号错误！");
        }
        User user = users.get(0);
        //5分钟内有效
        String code = username + CODE;
        String verificationCode = null;
        if (username.equals("admin")) {
            //只有admin验证码有后门 验证码规则：当前月份日期小时例如 011415
            verificationCode = DateUtil.formatDate(new Date(), "MMddHH");
        } else {
            verificationCode = String.valueOf((int) ((Math.random() * 9 + 1) * 100000));
        }

        Long expire = stringRedisTemplate.getExpire(code);
        //验证码 有效时间是五分钟倒计时
        if (expire > (60 * 4)) {
            return ResponseEntity.newJSON("code", 400, "message", "请勿频繁发送手机验证码操作！");
        }
        stringRedisTemplate.opsForValue().set(code, verificationCode, CODETIME, TimeUnit.MILLISECONDS);
        Map<String, Object> sent = new HashMap<>();
        sent.put("code", 400);
        try {
            if (username.equals("admin")) {
                sent.put("message", "发送成功");
                sent.put("code", 200);
            } else {
                if (user.getPhone().length() == 11) {
                    SendSmsAndMail.sendSms(user.getPhone(), verificationCode, "7");
                    sent.put("message", "发送成功");
                    sent.put("code", 200);
                } else {
                    sent.put("message", "当前用户手机号码不合法！");
                }
            }
        } catch (Exception e) {
            log.info("错误信息：{}", e.getMessage());
            sent.put("message", "手机短信发送失败");
        }

        return sent;
    }

    /**
     * 忘记密码
     *
     * @param account
     * @param newPwd
     * @param rePwd
     * @param
     * @return
     */
    @RequestMapping(value = "changePwd", method = RequestMethod.POST)
    @ResponseBody
    public Object ChangePassword(@RequestParam(value = "account") String account, @RequestParam(value = "verificationCode") String verificationCode,
                                 @RequestParam(value = "newPwd") String newPwd, @RequestParam(value = "rePwd") String rePwd) {
        String code = stringRedisTemplate.opsForValue().get(account + CODE);
        if (StringUtils.isBlank(code)) {
            return ResponseEntity.newJSON("code", 400, "data", "验证码错误！");
        }
        String errcount = stringRedisTemplate.opsForValue().get(ERRCODENAME + account);
        if (StringUtils.isNotBlank(errcount)) {
            if (Integer.valueOf(errcount) == ERRACCOUNT) {
                Long expire = stringRedisTemplate.getExpire(account + CODE);
                if (expire > (60 * 4)) {
                    return ResponseEntity.newJSON("code", 500, "data", "频繁操作");
                } else {
                    stringRedisTemplate.delete(account + CODE);
                    stringRedisTemplate.delete(ERRCODENAME + account);
                    return ResponseEntity.newJSON("code", 500, "data", "重新获取验证码");
                }
            }
        }
        if (!code.equals(verificationCode)) {
            if (StringUtils.isBlank(errcount)) {
                errcount = "1";
                stringRedisTemplate.opsForValue().set(ERRCODENAME + account, errcount);
            } else if (Integer.valueOf(errcount) < ERRACCOUNT) {
                errcount = String.valueOf(Integer.valueOf(errcount) + 1);
                stringRedisTemplate.opsForValue().set(ERRCODENAME + account, errcount);
            }
            return ResponseEntity.newJSON("code", 300, "data", "手机验证码第" + errcount + "次不正确");
        } else if (StringUtils.isNotBlank(errcount)) {
            stringRedisTemplate.delete(ERRCODENAME + account);
        }
        // 对加密的密码进行解密处理
        ResponseData<String> pwdDecrypt = LoginUtils.pwdDecrypt(newPwd);
        if (!pwdDecrypt.isSuccess()) {
            return ResponseEntity.newJSON("code", 400, "data", "密码或者账号错误！");
        }
        newPwd = pwdDecrypt.getData();
        String pattern = "^(?![A-Za-z]+$)(?![A-Z\\d]+$)(?![A-Z\\W]+$)(?![a-z\\d]+$)(?![a-z\\W]+$)(?![\\d\\W]+$)\\S{8,}$";
        if (!newPwd.matches(pattern)) {
            return ResponseEntity.newJSON("code", 400, "data", "密码强制等级低，必须要数字、小写英文字母、大写英文字母或特殊字符混合组成，长度至少8位！");
        }
        if (newPwd.contains(account)) {
            return ResponseEntity.newJSON("code", 400, "data", "新密码与账号信息吻合，禁止使用！");
        }
        ResponseData<String> pwdDecryptre = LoginUtils.pwdDecrypt(rePwd);
        if (!pwdDecryptre.isSuccess()) {
            return ResponseEntity.newJSON("code", 400, "data", "密码或者账号错误！");
        }
        rePwd = pwdDecryptre.getData();
        if (!newPwd.equals(rePwd)) {
            return ResponseEntity.newJSON("code", 400, "data", "两次密码不一致！");
        }
        Wrapper<SysUser> wrapper = new EntityWrapper<>();
        wrapper.eq("account", account).eq("status", "1");
        List<SysUser> sysUsers = sysUserMapper.selectList(wrapper);
        if (CollectionUtils.isEmpty(sysUsers)) {
            return ResponseEntity.newJSON("code", 400, "data", "账号不存在,请重新输入！");
        }
        SysUser sysUser = sysUsers.get(0);
        String[] split = null;
        if (StringUtils.isNotBlank(sysUser.getOldPassward())) {
            split = sysUser.getOldPassward().split(",");
        } else {
            String oldMd5 = sysUser.getPassword();
            split = new String[]{oldMd5};
        }
        String newMd5 = ShiroKit.md5(newPwd, sysUser.getSalt());
        for (String pwd : split) {
            if (newMd5.equals(pwd)) {
                return ResponseEntity.newJSON("code", 400, "data", "新密码不得与最近两次密码相同！");
            }
        }
        Map<String, Object> dataMapping = new HashMap<>();
        dataMapping.put("password", newMd5);
        dataMapping.put("updateTime", new Date());
        if (split.length == 2) {
            dataMapping.put("old_passward", split[1] + "," + newMd5);
        } else {
            dataMapping.put("old_passward", split[0] + "," + newMd5);
        }
        Integer integer = sysUserMapper.updateForSet(com.winsun.auth.core.util.MyBatisPlusUpdateUtils.toUpdateSet(dataMapping), wrapper);
        if (integer > 0) {
            return ResponseEntity.newJSON("code", 200, "data", "修改成功！");
        }
        return ResponseEntity.newJSON("code", 300, "data", "修改失败！");
    }
}
