package com.ynfy.app.api.v1.controller;

import cn.hutool.core.util.CharsetUtil;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.ynfy.app.api.v1.annoation.IgnoreAuth;
import com.ynfy.app.api.v1.entity.dto.UserInfo;
import com.ynfy.app.api.v1.entity.dto.WxLoginDTO;
import com.ynfy.app.api.v1.util.ApiUserUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.system.util.JwtUtil;
import org.jeecg.common.util.PasswordUtil;
import org.jeecg.common.util.RedisUtil;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.modules.base.service.BaseCommonService;
import org.jeecg.modules.system.entity.SysDepart;
import org.jeecg.modules.system.entity.SysUser;
import org.jeecg.modules.system.model.SysLoginModel;
import org.jeecg.modules.system.service.ISysDepartService;
import org.jeecg.modules.system.service.ISysUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.util.*;

@Api(tags = "API登录授权接口")
@RestController
@RequestMapping("/api/v1/auth")
@Slf4j
public class ApiAuthController {

    @Autowired
    private ISysUserService sysUserService;
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private ISysDepartService sysDepartService;
    @Resource
    private BaseCommonService baseCommonService;

    /**
     * app登录
     *
     * @param sysLoginModel
     * @return
     * @throws Exception
     */
    @IgnoreAuth
    @RequestMapping(value = "/login", method = RequestMethod.POST)
    public Result<JSONObject> login(@RequestBody SysLoginModel sysLoginModel) throws Exception {
        Result<JSONObject> result = new Result<JSONObject>();
        String username = sysLoginModel.getUsername();
        String password = sysLoginModel.getPassword();
        JSONObject obj = new JSONObject();

        //update-begin-author:taoyan date:2022-11-7 for: issues/4109 平台用户登录失败锁定用户
        if (isLoginFailOvertimes(username)) {
            return result.error500("该用户登录失败次数过多，请于10分钟后再次登录！");
        }
        //update-end-author:taoyan date:2022-11-7 for: issues/4109 平台用户登录失败锁定用户
        //1. 校验用户是否有效
        SysUser sysUser = sysUserService.getUserByName(username);
        result = sysUserService.checkUserIsEffective(sysUser);
        if (!result.isSuccess()) {
            return result;
        }

        //2. 校验用户名或密码是否正确
        String userpassword = PasswordUtil.encrypt(username, password, sysUser.getSalt());
        String syspassword = sysUser.getPassword();
        if (!syspassword.equals(userpassword)) {
            //update-begin-author:taoyan date:2022-11-7 for: issues/4109 平台用户登录失败锁定用户
            addLoginFailOvertimes(username);
            //update-end-author:taoyan date:2022-11-7 for: issues/4109 平台用户登录失败锁定用户
            result.error500("用户名或密码错误");
            return result;
        }

        //3.设置登录部门
        String orgCode = sysUser.getOrgCode();
        if (oConvertUtils.isEmpty(orgCode)) {
            //如果当前用户无选择部门 查看部门关联信息
            List<SysDepart> departs = sysDepartService.queryUserDeparts(sysUser.getId());
            //update-begin-author:taoyan date:20220117 for: JTC-1068【app】新建用户，没有设置部门及角色，点击登录提示暂未归属部，一直在登录页面 使用手机号登录 可正常
            if (departs == null || departs.size() == 0) {
				/*result.error500("用户暂未归属部门,不可登录!");
				return result;*/
            } else {
                orgCode = departs.get(0).getOrgCode();
                sysUser.setOrgCode(orgCode);
                this.sysUserService.updateUserDepart(username, orgCode, null);
            }
            //update-end-author:taoyan date:20220117 for: JTC-1068【app】新建用户，没有设置部门及角色，点击登录提示暂未归属部，一直在登录页面 使用手机号登录 可正常
        }

        //4. 设置登录租户
        Result<JSONObject> loginTenantError = sysUserService.setLoginTenant(sysUser, obj, username, result);
        if (loginTenantError != null) {
            return loginTenantError;
        }

        //5. 设置登录用户信息
        obj.put("userInfo", sysUser);

        //6. 生成token
        Map<String, Object> map = new HashMap();
        map.put("username", username);
        map.put("realname", sysUser.getRealname());
        map.put("userId", sysUser.getId());
        String token = JwtUtil.sign(map, syspassword);
        // 设置超时时间
        redisUtil.set(CommonConstant.PREFIX_USER_TOKEN + token, token);
        redisUtil.expire(CommonConstant.PREFIX_USER_TOKEN + token, JwtUtil.EXPIRE_TIME * 2 / 1000);

        //token 信息
        obj.put("token", token);
        result.setResult(obj);
        result.setSuccess(true);
        result.setCode(200);
        baseCommonService.addLog("用户名: " + username + ",登录成功[移动端]！", CommonConstant.LOG_TYPE_1, null);
        return result;
    }

    /**
     * 登录失败超出次数5 返回true
     *
     * @param username
     * @return
     */
    private boolean isLoginFailOvertimes(String username) {
        String key = CommonConstant.LOGIN_FAIL + username;
        Object failTime = redisUtil.get(key);
        if (failTime != null) {
            Integer val = Integer.parseInt(failTime.toString());
            if (val > 5) {
                return true;
            }
        }
        return false;
    }


    /**
     * 记录登录失败次数
     *
     * @param username
     */
    private void addLoginFailOvertimes(String username) {
        String key = CommonConstant.LOGIN_FAIL + username;
        Object failTime = redisUtil.get(key);
        Integer val = 0;
        if (failTime != null) {
            val = Integer.parseInt(failTime.toString());
        }
        // 10分钟
        redisUtil.set(key, ++val, 10);
    }

    /**
     * 微信登录
     */
    @ApiOperation(value = "微信登录")
    @IgnoreAuth
    @PostMapping("loginByWx")
    public Result<?> loginByWeixin(@RequestBody WxLoginDTO dto) {
        if (StringUtils.isBlank(dto.getCode())) {
            return Result.error("code不能为空");
        }
        UserInfo userInfo = dto.getUserInfo();
        //获取openid
        String requestUrl = ApiUserUtils.getWebAccess(dto.getCode());//通过自定义工具类组合出小程序需要的登录凭证 code
        log.info("》》》组合token为：" + requestUrl);
        JSONObject sessionData = JSON.parseObject(HttpUtil.get(requestUrl, CharsetUtil.CHARSET_UTF_8));

        if (Objects.isNull(sessionData) || StringUtils.isBlank(sessionData.getString("openid"))) {
            return Result.error("登录失败");
        }
        String openId = sessionData.getString("openid");
        SysUser wxUser = sysUserService.queryByOpenId(openId);
        if (Objects.isNull(wxUser)) {
            wxUser = new SysUser();
            wxUser.setCreateTime(new Date());//设置创建时间
            String salt = oConvertUtils.randomGen(8);
            wxUser.setSalt(salt);
            wxUser.setPassword("123456");
            wxUser.setUsername(openId);
            wxUser.setRealname("微信用户");
            String passwordEncode = PasswordUtil.encrypt(wxUser.getUsername(), wxUser.getPassword(), salt);
            wxUser.setPassword(passwordEncode);
            wxUser.setStatus(1);
            wxUser.setDelFlag(CommonConstant.DEL_FLAG_0);
            wxUser.setOpenId(openId);
            wxUser.setAvatar(!Objects.isNull(userInfo) ? userInfo.getAvatarUrl() : null);
            wxUser.setRealname(!Objects.isNull(userInfo) ? userInfo.getNickName() : null);
            sysUserService.save(wxUser);
        } else {
            wxUser.setAvatar(!Objects.isNull(userInfo) ? userInfo.getAvatarUrl() : null);
            wxUser.setRealname(!Objects.isNull(userInfo) ? userInfo.getNickName() : null);
            sysUserService.updateById(wxUser);
        }
        Result<JSONObject> result = new Result<JSONObject>();
        Map<String, Object> map = new HashMap();
        map.put("username", wxUser.getUsername());
        map.put("realname", wxUser.getRealname());
        map.put("userId", wxUser.getId());
        String token = JwtUtil.sign(map, wxUser.getPassword());

        JSONObject obj = new JSONObject();
        obj.put("userInfo", wxUser);
        //token 信息
        obj.put("token", token);
        result.setResult(obj);
        result.setSuccess(true);
        result.setCode(200);
        return result;
    }

}