package com.zd.auth.controller;

import cn.hutool.core.util.RandomUtil;
import com.zd.auth.form.LoginBody;
import com.zd.auth.form.RegisterBody;
import com.zd.auth.service.SysLoginService;
import com.zd.common.core.constant.*;
import com.zd.common.core.domain.R;
import com.zd.common.core.exception.CaptchaException;
import com.zd.common.core.exception.ServiceException;
import com.zd.common.core.utils.IdUtils;
import com.zd.common.core.utils.StringUtils;
import com.zd.common.core.web.domain.AjaxResult;
import com.zd.common.redis.service.RedisService;
import com.zd.common.security.service.TokenService;
import com.zd.system.api.RemoteUserService;
import com.zd.system.api.chemical.RemoteStockService;
import com.zd.system.api.domain.SysUser;
import com.zd.system.api.model.LoginUser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

import static com.zd.common.core.constant.Constants.CODE_EXPIRATION;

/**
 * token 控制
 *
 * @author zd
 */
@RestController
public class TokenController {

    private final Logger logger = LoggerFactory.getLogger(TokenController.class);
    @Autowired
    private TokenService tokenService;

    @Autowired
    private SysLoginService sysLoginService;

    @Autowired
    private RemoteUserService remoteUserService;

    @Autowired
    private RedisService redisService;

    @Resource
    private RemoteStockService stockService;
    @Resource
    private RedisTemplate<String,String> redisTemplate;

    @PostMapping("login")
    public R<?> login(@RequestBody LoginBody form) {
        // 用户登录
        String authType = form.getAuthType() == null ? Constants.GRANT_TYPE_PASSWORD : form.getAuthType();
        LoginUser userInfo;
        if (Objects.equals(authType, Constants.GRANT_TYPE_MOBILE)) {
            String key = Constants.DEFAULT_CODE_KEY +  Constants.GRANT_TYPE_MOBILE + "@" + form.getUsername();
            String code = redisTemplate.opsForValue().get(key);
            if (form.getPassword().equals(code)){
                R<LoginUser> userR = remoteUserService.getUserInfo(form.getUsername(), SecurityConstants.INNER);
                if (userR.getCode()== HttpStatus.SUCCESS &&userR.getData()!=null){
                    userInfo=userR.getData();
                }else {
                    throw new ServiceException("系统异常");
                }
            }else {
                throw new ServiceException("验证码不正确",503);
            }
        }else {
            userInfo = sysLoginService.login(form.getUsername(), UserConstants.USER_LOGIN_PC, form.getPassword());
        }
        userInfo.setLoginType(UserConstants.USER_LOGIN_PC);
        Map<String, Object> data = tokenService.createToken(userInfo);
        //这里判断输入的密码，是否和默认配置密码一样，如果一样，需要提示跳转设置密码
        AjaxResult resultPassword = remoteUserService.getConfigKey("sys.user.initPassword");
        if ((resultPassword.get("code") + "").equals("200")) {
            String defaultPassword = (String) resultPassword.get("msg");
            if (defaultPassword != null && defaultPassword.equals(form.getPassword())) {
                data.put("reset_password", true);
            } else {
                data.put("reset_password", false);
            }
        }
        // 区分大屏用户
        // 查询大屏链接
        AjaxResult result = remoteUserService.getRouters(userInfo.getUserid());

        try {
            List<Map<String, Object>> routers = (List<Map<String, Object>>) result.get("data");

            Map<String, Object> dataMenu = routers.stream().filter(
                    a -> "https://www.sxitdlc.com".equals(a.get("path") + "")).findFirst().orElse(null);
            if (dataMenu != null) {
                String tokenKey = "login_screen:";

                Integer type;
                if (userInfo.getSysUser().isAdmin()) {
                    type = 1;
                } else {
                    result = remoteUserService.selectAuthUserPower(userInfo.getUserid());
                    Map<String, Object> map = (Map<String, Object>) result.get("data");
                    type = Integer.parseInt(map.get("type") + "");
                }

                if (type == null) {
                    // 没有大屏权限
                    type = 3;
                    data.put("screen_token", "");
                } else if (redisService.hasKey(tokenKey + userInfo.getUserid())) {
                    String token = redisService.getCacheObject(tokenKey + userInfo.getUserid());
                    commLogin(userInfo, token);
                    data.put("screen_token", token);
                } else {
                    String token = IdUtils.fastUUID();
                    commLogin(userInfo, token);
                    redisService.setCacheObject(tokenKey + userInfo.getUserid(), token);
                    // 获取大屏TOKEN
                    data.put("screen_token", token);
                }

                data.put("screen_type", type);
            } else {
                // 没有大屏权限
                data.put("screen_type", 3);
                data.put("screen_token", "");
            }
        } catch (Exception e) {
            // 没有大屏权限
            data.put("screen_type", 3);
            data.put("screen_token", "");
        }
        // 获取登录token
        return R.ok(data);
    }

    //公共登录方法
    private void commLogin(LoginUser userInfo, String token) {
        LoginUser loginUser = new LoginUser();
        BeanUtils.copyProperties(userInfo, loginUser);
        loginUser.setToken(token);

        redisService.setCacheObject(CacheConstants.LOGIN_TOKEN_KEY + token, loginUser);
    }

    /**
     * 一体机登录
     * 小程序登录也在用
     */
    @PostMapping("/one/login")
    public R<?> oneLogin(@RequestBody LoginBody form) {
        // 用户登录
        LoginUser userInfo = sysLoginService.login(form.getUsername(), UserConstants.USER_LOGIN_WX, form.getPassword());
        userInfo.setLoginType(UserConstants.USER_LOGIN_WX);
        // 获取登录token
        return R.ok(tokenService.createProgramToken(userInfo));
    }

    /**
     * 发送验证码
     */
    @PostMapping("/send/code")
    public R<?> send(@RequestBody LoginBody form) {
        String username = form.getUsername();
        R<LoginUser> userR = remoteUserService.getUserInfo(username, SecurityConstants.INNER);
        if (userR.getCode()!=HttpStatus.SUCCESS || userR.getData()==null){
            throw new ServiceException("登录用户：" + username + " 不存在",530);
        }
        String key = Constants.DEFAULT_CODE_KEY +  Constants.GRANT_TYPE_MOBILE + "@" + username;
        String code = RandomUtil.randomNumbers(6);
        redisTemplate.opsForValue().set(key,code,CODE_EXPIRATION,TimeUnit.MINUTES);
        logger.info("========================>{}<=========================",code);
        String countKey=Constants.DEFAULT_CODE_KEY + "@" + username+"_COUNT";
        String count = redisTemplate.opsForValue().get(countKey);
        if (StringUtils.isEmpty(count)){
            redisTemplate.opsForValue().set(countKey,"1",60,TimeUnit.MINUTES);
        }else {
            if (count!=null){
                int i=Integer.parseInt(count);
                if (i>=5){
                    throw new ServiceException("验证码发送超过限制，请一小时后再试",530);
                }
                i++;
                redisTemplate.opsForValue().set(countKey,i+"",60,TimeUnit.MINUTES);
            }
        }
        return stockService.sendSydSms(code, 2, null, form.getUsername());
    }

    /**
     * 学习一体机 用户端登录
     * 接口修改为分两步操作，1 刷卡获取人员信息和token , 2 人脸验证之后再调用一次实现真实登录
     * type : 1 和 2
     */
    @PostMapping("/learn/login")
    public R<?> learnLogin(HttpServletRequest request, @RequestBody Map<String, Object> params) {
        int type = org.apache.commons.lang3.StringUtils.isNotBlank((String) params.get("type")) ? Integer.parseInt((String) params.get("type")) : 1;

        String machineCode = params.get("machineCode") == null ? "" : (String) params.get("machineCode");
        // 用户登录
        String username = (String) params.get("userName");

        int aioType = params.get("aioType") == null ? UserConstants.USER_LOGIN_AIO : Integer.parseInt(params.get("aioType") + "");

        logger.error("学习机登录，加密前：" + username + "，设备编码：" + machineCode);
        if (UserConstants.USER_LOGIN_HXP == aioType) {
            // TODO 终端传参数据有问题，暂临时后端处理
//            username = username.replaceAll("%00", "")
//                    .replaceAll("%02", "")
//                    .replaceAll("%03", "")
//                    .replaceAll("%0A", "")
//                    .replaceAll("%0D", "")
//                    .trim();
        } else {
            // 查询用户信息
            if (StringUtils.isNumeric(username)) {
                username = Long.toHexString(Long.parseLong(username)).toUpperCase();
                logger.error("学习机登录，加密后：" + username);
            } else {
                logger.error("通过卡号未找到用户");
                return R.fail("无效卡号或未绑定用户，请联系管理员！");
            }
        }

        R<SysUser> user = remoteUserService.getUserInfoByCardNum(username, SecurityConstants.INNER);

        if (R.FAIL == user.getCode()) {
            throw new ServiceException(user.getMsg());
        }
        if (StringUtils.isNull(user.getData())) {
            return R.fail("登录用户不存在！");
        }


        R<LoginUser> userResult = remoteUserService.getUserInfo(user.getData().getUserName(), aioType, SecurityConstants.INNER);

        if (R.FAIL == userResult.getCode() || 503 == userResult.getCode()) {
            return R.fail(userResult.getMsg());
        }

        if (userResult.getData() != null) {

            LoginUser userInfo = userResult.getData();
            userInfo.setLoginType(aioType);
            userInfo.setMachineCode(machineCode);
            if (userInfo.getSysUser() == null) {
                return R.fail("登录用户不存在！");
            }

            Map<String, Object> map = null;
            if (type == 1) {
                // 获取登录token
                map = tokenService.createToken(userInfo);
            } else if (type == 2) {
                // 资源删除
                LoginUser loginUser = tokenService.getLoginUser(request);
                if (StringUtils.isNotNull(loginUser)) {
                    // 删除用户缓存记录
                    tokenService.delLoginUser(loginUser.getToken());
                }

                map = tokenService.createToken(userInfo);

                if (UserConstants.USER_LOGIN_HXP == aioType) {
                    map.put("positionName", userInfo.getSysUser().getPositionName());
                    map.put("cabinetLock", userInfo.isCabinetLock());
                    map.put("airBottle", userInfo.isAirBottle());
                } else if (UserConstants.USER_LOGIN_AIO == aioType) {
                    if (redisService.hasKey(CacheConstants.LEARN_USER_KEY + userInfo.getSysUser().getUserId())) {
                        LoginUser userCache = redisService.getCacheObject(CacheConstants.LEARN_USER_KEY + userInfo.getSysUser().getUserId());
                        if (!machineCode.equals(userCache.getMachineCode())) {
                            return R.fail("签到失败，不能重复签到！");
                        }
                    }
                    // 记录学习一体机用户登录状态
                    redisService.setCacheObject(CacheConstants.LEARN_USER_KEY + userInfo.getSysUser().getUserId(), userInfo, Constants.TOKEN_EXPIRE * 60, TimeUnit.SECONDS);
                }
            }

            return R.ok(map);
        } else {
            return R.fail("登录用户不存在！");
        }

    }

    /**
     * 学习一体机 用户退出登录
     */
    @PostMapping("/learn/loginOut")
    public R<?> learnLoginOut(HttpServletRequest request) {

        LoginUser loginUser = tokenService.getLoginUser(request);
        if (StringUtils.isNotNull(loginUser)) {
            SysUser user = loginUser.getSysUser();
            // 删除用户缓存记录
            tokenService.delLoginUser(loginUser.getToken());
            // 记录用户退出日志
            sysLoginService.logout(user);
            // 删除一体机登录状态
            redisService.deleteObject(CacheConstants.LEARN_USER_KEY + loginUser.getUserid());
        }
        return R.ok();
    }

    @DeleteMapping("logout")
    public R<?> logout(HttpServletRequest request) {
        LoginUser loginUser = tokenService.getLoginUser(request);
        if (StringUtils.isNotNull(loginUser)) {
            SysUser user = loginUser.getSysUser();
            // 删除用户缓存记录
            tokenService.delLoginUser(loginUser.getToken());
            // 记录用户退出日志
            sysLoginService.logout(user);
        }
        return R.ok();
    }

    @PostMapping("refresh")
    public R<?> refresh(HttpServletRequest request) {
        LoginUser loginUser = tokenService.getLoginUser(request);
        if (StringUtils.isNotNull(loginUser)) {
            // 刷新令牌有效期
            tokenService.refreshToken(loginUser);
            return R.ok();
        }
        return R.ok();
    }

    @PostMapping("register")
    public R<?> register(@RequestBody RegisterBody registerBody) {
        // 用户注册
        sysLoginService.register(registerBody.getUsername(), registerBody.getPassword());
        return R.ok();
    }
}
