package com.pj.project.app_user;

import cn.dev33.satoken.spring.SpringMVCUtil;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.DigestUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.IService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.pj.api.client.level_one_server.LevelOneServerInterface;
import com.pj.api.client.level_two_server.LevelTwoServerInterface;
import com.pj.api.client.transport.TransportInterface;
import com.pj.api.consts.FeignFactory;
import com.pj.api.dto.*;
import com.pj.common.core.exception.ServiceException;
import com.pj.common.core.utils.StringUtils;
import com.pj.current.config.SystemObject;
import com.pj.current.dto.APPLoginUserInfo;
import com.pj.current.satoken.StpAPPUserUtil;
import com.pj.current.satoken.StpUserUtil;
import com.pj.enummj.DeleteStatus;
import com.pj.enummj.IsLock;
import com.pj.enummj.UserType;

import com.pj.project.app_user.dto.*;
import com.pj.project.app_user.vo.AppUserVo;
import com.pj.project.app_user_login_log.AppUserLoginLog;
import com.pj.project.app_user_login_log.AppUserLoginLogService;
import com.pj.project.re_role_menu.ReRoleMenu;
import com.pj.project.re_role_menu.ReRoleMenuMapper;
import com.pj.project4sp.face.factory.FaceFactory;
import com.pj.project4sp.face.handler.VerifyVO;
import com.pj.project4sp.utils.ImageUtils;
import com.pj.utils.Aes;
import com.pj.utils.cache.RedisUtil;
import com.pj.utils.sg.AjaxError;
import com.pj.utils.sg.AjaxJson;
import com.pj.utils.sg.WebNbUtil;
import com.pj.utils.so.SoMap;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;


/**
 * Service: app_user -- 移动端账号
 *
 * @author qzy
 */
@Service
@Transactional(rollbackFor = Exception.class)
@Slf4j
public class AppUserService extends ServiceImpl<AppUserMapper, AppUser> implements IService<AppUser> {

    /**
     * 底层 Mapper 对象
     */
    @Autowired
    AppUserMapper appUserMapper;
    /**
     * 密码加密模式
     */
    @Autowired
    private PasswordEncoder passwordEncoder;
    //权限字符
    @Autowired
    private ReRoleMenuMapper reRoleMenuMapper;
    /**
     * 方法抽取
     */
    @Autowired
    private MethodAppUserService methodAppUserService;
    /**
     * 阿里云验证码
     */
    @Autowired
    private FaceFactory faceFactory;
    @Autowired
    private LevelOneServerInterface levelOneServerInterface;
    @Autowired
    private LevelTwoServerInterface levelTwoServerInterface;
    @Autowired
    private TransportInterface transportInterface;
    @Autowired
    AppUserLoginLogService appUserLoginLogService;


    /**
     * 验证码前缀
     */
    String PREFIX = "app_user:phone:sms_code:";


    /**
     * 改
     */
    void update(AppUser a) {
        a.setUpdateTime(new Date());
        updateById(a);

    }

    /**
     * 修改密码
     *
     * @param dto
     * @return
     */
    boolean pass(PassDto dto) {
        AppUser user = new AppUser();
        user.setId(dto.getId());
        user.setUpdateTime(new Date());
        user.setPassword(passwordEncoder.encode(dto.getPassword()));
        return updateById(user);
    }

    /**
     * 查
     */
    AppUser getById(Long id) {
        return super.getById(id);
    }

    /**
     * 个人中心-个人详细信息
     *
     * @return
     */
    AppUserVo getSelfInfo() {
        if (StpAPPUserUtil.getAPPLoginInfo().getFk() == null) {
            return null;
        }
        //查询当前人
        AppUser appUser = appUserMapper.selectById(StpAPPUserUtil.getAPPLoginInfo().getLoginId());
        if (appUser == null) throw new ServiceException("当前用户信息异常!");
        //获取当前组
        //创建返回值对象
        AppUserVo appUserVo = new AppUserVo();
        //根据身份获取不同名称
        appUserVo.setFk(appUser.getFkId());
        methodAppUserService.getRoleName(appUserVo, appUser.getUserType());
        //设置属性
        appUserVo.setPhone(appUser.getPhone());
        appUserVo.setName(appUser.getName());

        return appUserVo;
    }

    /**
     * 查询单个APP有效用户
     */
    public AppUserDto getUserById(Long id) {
        //查单个
        AppUser appUser = appUserMapper.selectById(id);
        if (appUser == null) return null;
        //判断有效性
        if (!appUser.getStatus().equals("0") && appUser.getDeleteStatus() != 0) {
            AppUserDto appUserDto = new AppUserDto();
            BeanUtils.copyProperties(appUser, appUserDto);
            return appUserDto;
        }
        return null;
    }

    public AppUserDto getAppUserByFkId(Long fkId) {
        LambdaQueryWrapper<AppUser> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(AppUser::getFkId, fkId);
        List<AppUser> appUserList = appUserMapper.selectList(queryWrapper);

        AppUserDto appUserDto = new AppUserDto();
        if (appUserList.size() == 0) return appUserDto;

        AppUser appUser = appUserList.get(0);
        BeanUtils.copyProperties(appUser, appUserDto);
        return appUserDto;
    }

    /**
     * 查集合 - 根据条件（参数为空时代表忽略指定条件）
     */
    List<AppUser> getList(SoMap so) {
        return appUserMapper.getList(so);
    }

    /**
     * 启/停边民的app账号登陆限制
     */
    int isLock(String id, Integer type, Integer status) {
        //查询
        LambdaQueryWrapper<AppUser> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(AppUser::getFkId, id);
        queryWrapper.eq(AppUser::getUserType, type);
        AppUser appUser1 = appUserMapper.selectList(queryWrapper).get(0);
        if (appUser1 == null) throw new RuntimeException("您进行修改的用户不存在!");
        //设置状态
        appUser1.setStatus(String.valueOf(status));
        //保存
        int i = appUserMapper.updateById(appUser1);
        return i;
    }

    /**
     * 注册
     */
    boolean register(RegisterDto registerDto) {
        if (registerDto == null) return false;
        registerDto.setPhone(Aes.aesDecrypt(registerDto.getPhone()));
        //手机号去重
        String phone = registerDto.getPhone();
        if (appUserMapper.selectList(new LambdaQueryWrapper<AppUser>().eq(AppUser::getPhone, phone).eq(AppUser::getDeleteStatus, DeleteStatus.DELETE_STATUS_ON.getCode())).size() != 0)
            throw new RuntimeException("当前手机号已被注册!");
        //开始进行实际注册
        //1. 查询数据库内是否存在逻辑删除
        List<Long> collect = appUserMapper.selectList(new LambdaQueryWrapper<AppUser>().eq(AppUser::getPhone, phone).eq(AppUser::getDeleteStatus, DeleteStatus.DELETE_STATUS_OFF.getCode())).stream().map(AppUser::getId).collect(Collectors.toList());
        //删除旧数据
        if (collect.size() > 0) appUserMapper.deleteBatchIds(collect);
        //2.校验密码
        if (!registerDto.getPassword().equals(registerDto.getRePassword()))
            throw new RuntimeException("两次密码校验不通过!");
        //3.校验短信验证码
        String smsCode = RedisUtil.get(PREFIX + registerDto.getPhone());
        if (smsCode == null) throw new RuntimeException("验证码已过期,请重新发送!");
        //比对验证码
        if (registerDto.getSmsCode() != Integer.parseInt(smsCode))
            throw new SecurityException("验证码输入错误,请检查!");
        //4.开始新增
        AppUser appUser = new AppUser();
        //手机号
        appUser.setPhone(phone);
        //注册身份
        appUser.setUserType(registerDto.getType());
        //加密并设置登陆密码
        String password = Aes.aesDecrypt(registerDto.getPassword());
        String encode = passwordEncoder.encode(password);
        appUser.setPassword(encode);
        //创建单位
        appUser.setCreateUnit("数据分中心");
        //昵称
        appUser.setName(registerDto.getNickName());
        //创建时间
        appUser.setCreateTime(new Date());
        //默认可用
        appUser.setStatus("1");
        appUser.setDeleteStatus(DeleteStatus.DELETE_STATUS_ON.getCode());
        //保存
        int insert = appUserMapper.insert(appUser);
        return insert == 1;
    }

    /**
     * 用户登录
     */
    AjaxJson login(LoginDto dto) {
        dto.setPhone(Aes.aesDecrypt(dto.getPhone()));
        //登陆日志信息
        AppUserLoginLog loginLog = new AppUserLoginLog();
        BeanUtils.copyProperties(dto, loginLog);
        loginLog.setCreateTime(new Date());
        loginLog.setUserName(dto.getPhone());
        loginLog.setLoginIp(WebNbUtil.getIP(SpringMVCUtil.getRequest()));
        //登陆查询
        LambdaQueryWrapper<AppUser> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(AppUser::getPhone, dto.getPhone());  // 手机号码
        queryWrapper.eq(AppUser::getDeleteStatus, DeleteStatus.DELETE_STATUS_ON.getCode()); //未被逻辑删除
        List<AppUser> userList = appUserMapper.selectList(queryWrapper);
        if (userList.size() == 0) {
            loginLog.setStatus("0");
            appUserLoginLogService.save(loginLog);
            return AjaxJson.getError("该用户不存在,请先注册!");
        }
        //判断用户是否存在
        if (userList.size() > 1) {
            log.debug("该手机号登录用户存在多个活动账号,手机号: " + dto.getPhone());
            return AjaxJson.getError("该账户存在问题,请联系客服进行处理!");
        }
        //获取登录用户
        AppUser appUser = userList.get(0);
        if (appUser.getFace() == 1) {
            // return AjaxJson.getError("该账号只支持人脸登录");
        }
        //比对密码
        String userPassword = appUser.getPassword();
        boolean matches = passwordEncoder.matches(Aes.aesDecrypt(dto.getPassword()), userPassword);
        if (!matches) {
            loginLog.setStatus("1");
            appUserLoginLogService.save(loginLog);
            return AjaxJson.getError("用户名或密码错误,请检查!");
        }
        //判断是否停用
        if (appUser.getStatus().equals("0")) {
            loginLog.setStatus(IsLock.IS_LOCK_OFF.getCode() + "");
            appUserLoginLogService.save(loginLog);
            return AjaxJson.getError("该账户 " + appUser.getPhone() + " 已停用!");
        }
        //设置登录次数
        appUser.setLoginCount(appUser.getLoginCount() + 1);
        //设置登陆时间
        appUser.setLastLoginTime(new Date());
        //保存
        appUserMapper.updateById(appUser);

        //开始执行登录
        StpAPPUserUtil.login(appUser.getId());
        // 组织返回参数,直接拿过来用的,然后自己改吧改吧
        SoMap map = new SoMap();
        //敏感信息置空
        appUser.setPassword(null);
        //执行
        map.put("appUser", appUser);
        //获取当前用户角色权限字符
        List<ReRoleMenu> reRoleMenus = reRoleMenuMapper.selectList(new LambdaQueryWrapper<ReRoleMenu>().eq(ReRoleMenu::getAppRoleId, appUser.getUserType()));
        //使用stream流对其reRoleMenus集合的权限字符进行过滤顺便转成String类型
        List<String> per_list = reRoleMenus.stream().map(ReRoleMenu::getAppMenuId).collect(Collectors.toList()).stream().map(String::valueOf).collect(Collectors.toList());
//		if(reRoleMenus.size() == 0)return AjaxJson.getError("当前职务暂无权限!");
        //过滤出权限字符
        map.put("per_list", per_list);
        map.put("tokenInfo", StpAPPUserUtil.getTokenInfo());
//		StpAPPUserUtil.cachePerList(per_list);
        APPLoginUserInfo info = new APPLoginUserInfo();
        //获取区域
        switch (appUser.getUserType()) {
            case 1:
                PeopleDto rpcById = levelOneServerInterface.getRpcById(appUser.getFkId());
                if (rpcById != null) {
                    info.setTradeAreaId(rpcById.getTradeAreaId());
                    info.setTradeAreaName(rpcById.getTradeAreaName());
                }
                break;
            case 2:
                PeopleDto leader = levelOneServerInterface.getRpcById(appUser.getFkId());
                if (leader != null) {
                    info.setTradeAreaId(leader.getTradeAreaId());
                    info.setTradeAreaName(leader.getTradeAreaName());
                }
                break;
            case 3:
                System.out.println("收购商无互市区字段");
                break;
            case 4:
                DriverDto driver = transportInterface.getByDriverId(appUser.getFkId());
                if (driver != null) {
                    info.setTradeAreaId(driver.getTradeAreaId());
                    info.setTradeAreaName(driver.getTradeAreaName());
                }
                break;
            case 5:
                EnterpriseDto enterprise = levelOneServerInterface.getEnterpriseById(appUser.getFkId());
                if (enterprise != null) {
                    info.setTradeAreaId(enterprise.getTradeAreaId());
                    info.setTradeAreaName(enterprise.getTradeAreaName());
                }
                break;
            case 6:
                CooperativeDto cooperative = levelOneServerInterface.getCooperativeById(appUser.getFkId());
                if (cooperative != null) {
                    info.setTradeAreaId(cooperative.getTradeAreaId());
                    info.setTradeAreaName(cooperative.getTradeAreaName());
                }
                break;
            default:
                throw new SecurityException("身份信息有误");
        }

        info.setLoginId(appUser.getId());
        info.setLoginName(appUser.getName());
        info.setFk(appUser.getFkId());
        info.setUserType(appUser.getUserType());
        StpAPPUserUtil.cacheAPPLoginInfo(info);
        return AjaxJson.getSuccessData(map);
    }


    /**
     * 忘记密码
     */
    AjaxJson forgetPassword(ForgetPasswordDto forgetPasswordDto) {
        //进行查询
        List<AppUser> appUserList = appUserMapper.selectList
                (new LambdaQueryWrapper<AppUser>().eq(AppUser::getPhone, forgetPasswordDto.getPhone())
                        .eq(AppUser::getDeleteStatus, DeleteStatus.DELETE_STATUS_ON.getCode())
                        .eq(AppUser::getStatus, IsLock.IS_LOCK_ON.getCode()));
        //判断其手机号码可能存在的异常情况
        if (appUserList.size() > 1)
            return AjaxJson.getError("当前账户存在异常,请联系客服进行处理!");
        if (appUserList.size() == 0) throw new RuntimeException("您当前手机号尚未进行注册!");
        //获取当前手机号对象
        AppUser appUser = appUserList.get(0);
        //从缓存中获取验证码
        String smsCode = RedisUtil.get(PREFIX + forgetPasswordDto.getPhone());
        if (smsCode == null) return AjaxJson.getError("验证码已过期!");
        //比对用户输入的验证码
        boolean result = smsCode.equals(forgetPasswordDto.getSmsCode());
        //进行验证码校验完成后的流程
        if (result) {
            //密码校验
            boolean equals = forgetPasswordDto.getPassword().equals(forgetPasswordDto.getRePassword());
            //验证码匹配成功,执行修改密码逻辑
            //1.判断其密码验证
            if (equals) {
                //1.1 密码校验正确,设置新密码
                String encode = passwordEncoder.encode(forgetPasswordDto.getRePassword());
                appUser.setPassword(encode);
                //1.2  执行保存
                int i = appUserMapper.updateById(appUser);
                if (i != 1) return AjaxJson.getError("密码重置失败!");
                return AjaxJson.getSuccess("密码找回成功!");
            } else {

                return AjaxJson.getError("两次密码校验不匹配,请重新尝试!");

            }

        }

        //验证码匹配错误
        return AjaxJson.getError("验证码输入错误,请检查!");
    }

    /**
     * 获取验证码
     */
    boolean getPhoneSmsCode(String phone) {
        AppUser appUser = this.findByPhone(phone);
        if (appUser != null) {
            throw new AjaxError("该手机号已注册");
        }
        //生成4位随机数
        String code = RandomUtil.randomNumbers(4);
        //保存到缓存,默认1分钟 todo:届时放开手机验证码 randomNumber
        RedisUtil.setByMINUTES(PREFIX + phone, code, 5);
        SystemObject.smsFactory.handler().sendSMS(phone, "您的验证码是" + code + "。如非本人操作，请忽略本短信");
        //发送验证码短信
        return true;

    }

    private AppUser findByPhone(String phone) {
        QueryWrapper<AppUser> ew = new QueryWrapper<>();
        ew.lambda().eq(AppUser::getPhone, phone);
        List<AppUser> list = list(ew);
        return list.isEmpty() ? null : list.get(0);
    }


    /**
     * 更换角色
     */
    AjaxJson updateRole(String appRoleId) {
        // 获取当前用户角色权限字符
        List<ReRoleMenu> reRoleMenus = reRoleMenuMapper.selectList(new LambdaQueryWrapper<ReRoleMenu>().eq(ReRoleMenu::getAppRoleId, appRoleId));
        // 使用stream流对其reRoleMenus集合的权限字符进行过滤顺便转成String类型
        List<String> per_list = reRoleMenus.stream().map(ReRoleMenu::getAppMenuId).collect(Collectors.toList()).stream().map(String::valueOf).collect(Collectors.toList());
        if (reRoleMenus.size() == 0) return AjaxJson.getError("当前用户角色暂无权限!");

        SoMap map = new SoMap();
        map.put("per_list", per_list);
        StpUserUtil.cachePerList(per_list);

        return AjaxJson.getSuccessData(map);
    }

    /**
     * 退出登录
     *
     * @return
     */
    public String logout() {
        StpAPPUserUtil.logout();
        return "退出登录成功!";
    }

    /**
     * 修改密码
     *
     * @param oldPassword 旧密码
     * @param newPassword 新密码
     * @param rePassword  确认密码
     * @return
     */
    public boolean modifyPassword(String oldPassword, String newPassword, String rePassword) {
        //对比新密码和确认密码
        if (!newPassword.equals(rePassword)) throw new ServiceException("新密码和确认密码不一致!");

        //获取user
        APPLoginUserInfo appLoginInfo = StpAPPUserUtil.getAPPLoginInfo();
        AppUser appUser = appUserMapper.selectById(appLoginInfo.getLoginId());
        if (appUser == null) throw new SecurityException("当前账户信息异常!");
        //旧密码比对
        boolean result = passwordEncoder.matches(oldPassword, appUser.getPassword());
        if (!result) throw new SecurityException("旧密码输入错误!");
        //新密码进行编码
        String password = passwordEncoder.encode(newPassword);
        //执行修改
        appUser.setPassword(password);
        //设置基本属性
        appUser.setUpdateTime(new Date());
        //保存
        return 1 == appUserMapper.updateById(appUser);
    }

    /**
     * 获取银行卡信息
     */
    public SoMap getBankInfo() {
        SoMap so = new SoMap();
        Integer userType = StpAPPUserUtil.getAPPLoginInfo().getUserType();
        Long fk = StpAPPUserUtil.getAPPLoginInfo().getFk();

        //1=普通边民,2=边民组长,3=收购商,4=司机,5=外籍商户,6=合作社
        if (1 == userType || 2 == userType) {
            PeopleDto peopleDto = levelOneServerInterface.getRpcById(fk);
            so.put("bankName", peopleDto.getBankName());
            so.put("bankAccount", peopleDto.getBankCode());
        } else if (3 == userType) {
            PurchaserDto purchaserDto = levelTwoServerInterface.getByPurchaserId(fk);
            so.put("bankName", purchaserDto.getBankName());
            so.put("bankAccount", purchaserDto.getBankAccount());
        } else if (5 == userType) {
            EnterpriseDto enterpriseDto = levelOneServerInterface.getEnterpriseById(fk);
            so.put("bankName", enterpriseDto.getBank());
            so.put("bankAccount", enterpriseDto.getBankAccount());
        } else if (6 == userType) {
            CooperativeDto cooperativeDto = levelOneServerInterface.getCooperativeById(fk);
            so.put("bankName", cooperativeDto.getBankName());
            so.put("bankAccount", cooperativeDto.getBankAccount());
        }
        return so;
    }

    /**
     * 保存银行卡信息
     */
    public boolean saveBankInfo(SoMap so) {
        Integer userType = StpAPPUserUtil.getAPPLoginInfo().getUserType();
        Long fk = StpAPPUserUtil.getAPPLoginInfo().getFk();
        String bankName = so.getString("bankName");
        String bankAccount = so.getString("bankAccount");

        //1=普通边民,2=边民组长,3=收购商,4=司机,5=外籍商户,6=合作社
        if (1 == userType || 2 == userType) {
            boolean result = levelOneServerInterface.saveBankByPeople(fk, bankName, bankAccount);
            return result;
        } else if (3 == userType) {
            boolean result = levelTwoServerInterface.saveBankByPurchaser(fk, bankName, bankAccount);
            return result;
        } else if (5 == userType) {
            boolean result = levelOneServerInterface.saveBankByEnterprise(fk, bankName, bankAccount);
            return result;
        } else if (6 == userType) {
            boolean result = levelOneServerInterface.saveBankByCooperative(fk, bankName, bankAccount);
            return result;
        }
        return false;
    }

    /**
     * 远程调用: 收购商认证
     */
    public AppUserDto getByPhoneAndUserType(String phone, Integer userType) {
        List<AppUser> appUsers = appUserMapper.selectList(new LambdaQueryWrapper<AppUser>().eq(AppUser::getPhone, phone).eq(AppUser::getUserType, userType).eq(AppUser::getDeleteStatus, DeleteStatus.DELETE_STATUS_ON.getCode()).eq(AppUser::getStatus, 1));
        if (appUsers.size() != 1) throw new ServiceException("用户信息有误。");
        AppUserDto appUserDto = new AppUserDto();
        BeanUtils.copyProperties(appUsers.get(0), appUserDto);
        return appUserDto;
    }

    /**
     * 远程调用: 保存appUser信息
     */
    public boolean saveAppUserInfo(AppUserDto appUser) {
        AppUser user = new AppUser();
        BeanUtils.copyProperties(appUser, user);
        int update = appUserMapper.updateById(user);
        return update == 1;
    }


    /**
     * 用户数量统计
     *
     * @return
     */
    public Map<String, Object> selectUsers() {
        return appUserMapper.selectUsers();
    }

    ;

    /**
     * 创建账号
     *
     * @param createDTO
     */
    public boolean createUser(AppUserCreateDTO createDTO) {
        log.info("创建APP账号:{}", JSONUtil.toJsonStr(createDTO));
        String phone = createDTO.getPhone().trim();
        if (StringUtils.isEmpty(phone)) {
            log.info("创建APP账号失败: 手机号不能为空");
            return false;
        }
        AppUser appUser = this.findByPhone(phone);
        if (appUser != null) {
            log.info("创建APP账号失败:当前账号的手机号码已存在！！！");
            return false;
        }
        appUser = new AppUser();
        BeanUtils.copyProperties(createDTO, appUser);
        //密码加密
        String encodePassword = passwordEncoder.encode(phone);
        appUser.setPassword(encodePassword)
                .setFkId(createDTO.getFkId())
                .setUserType(Integer.parseInt(createDTO.getUserType()))
                .setDeleteStatus(DeleteStatus.DELETE_STATUS_ON.getCode())
                .setCreateTime(new Date());
        String content = "您好,您的app账号已生成。账号:" + phone + ", 初始密码:" + phone + "。可前往app进行修改";
        // todo 发送短信
        SystemObject.smsFactory.handler().sendSMS(phone, content);
        return this.save(appUser);
    }


    public void authFace(Long loginId, MultipartFile file, Integer type) throws IOException {
        String img;
        try (InputStream is = file.getInputStream()) {
            img = Base64.encode(is);

        } catch (IOException e) {
            throw new AjaxError("识别失败");
        }
        byte[] images = ImageUtils.resizeByteImageBase64(img);
        boolean hasPerson = faceFactory.handler().checkHasPerson(images);
        if (!hasPerson) {
            throw new AjaxError("请正视摄像头");
        }
        if (type == 2) {
            AppUser db = getById(loginId);
            VerifyVO result = faceFactory.handler().verify(db.getFaceId(), images);
            if (!result.isSuccess()) {
                if (result.getMsg().contains("人员ID不存在")) {
                    faceFactory.handler().createPersonByBase(db.getFaceId(), db.getName(), images);
                    return;
                }
                log.info("Verification:{},{}", loginId);
                throw new AjaxError("人脸不匹配");
            }
            return;
        }
        String faceId = RandomUtil.randomString(32);
        AppUser appUser = this.getById(loginId);
        appUser.setFace(1);
        appUser.setFaceTime(new Date()).setFaceId(faceId);
        this.updateById(appUser);
        faceFactory.handler().createPersonByBase(faceId, appUser.getName(), images);
    }

    /**
     * tencen:
     * secret_id: 'AKIDtmacfdOH97likhhaL971xywwhRH7saCt'
     * secret_key: '1DOSWWYcl2FWhw7BLOII6zz65ylOzTpS'
     * groupId: 'gds4f56ds79w1g2d45'
     * groupName: '天保物流'
     *
     * @param loginId
     * @param img
     * @param type
     */
    public void authFace(Long loginId, String img, Integer type) throws IOException {
        byte[] byteImageBase64 = ImageUtils.resizeByteImageBase64(img);
        boolean hasPerson = faceFactory.handler().checkHasPerson(byteImageBase64);
        if (!hasPerson) {
            throw new AjaxError("请正视摄像头");
        }
        if (type == 2) {
            AppUser db = getById(loginId);
            String faceId = db.getFaceId();
            if (StrUtil.isEmpty(faceId)) {
                throw new AjaxError("人脸未录入");
            }
            VerifyVO result = faceFactory.handler().verify(faceId, byteImageBase64);
            if (!result.isSuccess()) {
                if (result.getMsg().contains("人员ID不存在")) {
                    faceFactory.handler().createPersonByBase(faceId, db.getName(), byteImageBase64);
                    return;
                }
                log.info("Verification:{},{}", loginId, img);
                throw new AjaxError(result.getMsg());
            }
            return;
        }
        AppUser appUser = this.getById(loginId);
        if (StrUtil.isNotEmpty(appUser.getFaceId()) && appUser.getFace() == 1) {
            faceFactory.handler().deletePerson(appUser.getFaceId());
        }
        String faceId = RandomUtil.randomString(32);
        appUser.setFace(1);
        appUser.setFaceTime(new Date()).setFaceId(faceId);
        this.updateById(appUser);
        faceFactory.handler().createPersonByBase(faceId, appUser.getName(), byteImageBase64);
    }

    public AjaxJson faceLogin(MultipartFile file) {
        String img;
        try (InputStream is = file.getInputStream()) {
            img = Base64.encode(is);

        } catch (IOException e) {
            throw new AjaxError("识别失败");
        }
        List<String> faceId = faceFactory.handler().faceSearch(img);
        if (faceId.isEmpty()) {
            return AjaxJson.getError("人员未录入人脸");
        }
        AppUser appUser = findByFaceId(faceId.get(0));
        if (appUser == null) {
            return AjaxJson.getError("人员信息未找到");
        }
        if (appUser.getUserType() != 1) {
            return AjaxJson.getError("当前用户不支持人脸登录");
        }
        AppUserLoginLog loginLog = new AppUserLoginLog();
        loginLog.setCreateTime(new Date());
        loginLog.setUserName(appUser.getPhone());
        loginLog.setLoginIp(WebNbUtil.getIP(SpringMVCUtil.getRequest()));
        appUserLoginLogService.save(loginLog);
        //设置登录次数
        appUser.setLoginCount(appUser.getLoginCount() + 1);
        //设置登陆时间
        appUser.setLastLoginTime(new Date());
        //保存
        appUserMapper.updateById(appUser);

        //开始执行登录
        StpAPPUserUtil.login(appUser.getId());
        // 组织返回参数,直接拿过来用的,然后自己改吧改吧
        SoMap map = new SoMap();
        //敏感信息置空
        appUser.setPassword(null);
        //执行
        map.put("appUser", appUser);
        //获取当前用户角色权限字符
        List<ReRoleMenu> reRoleMenus = reRoleMenuMapper.selectList(new LambdaQueryWrapper<ReRoleMenu>().eq(ReRoleMenu::getAppRoleId, appUser.getUserType()));
        //使用stream流对其reRoleMenus集合的权限字符进行过滤顺便转成String类型
        List<String> per_list = reRoleMenus.stream().map(ReRoleMenu::getAppMenuId).collect(Collectors.toList()).stream().map(String::valueOf).collect(Collectors.toList());
        //过滤出权限字符
        map.put("per_list", per_list);
        map.put("tokenInfo", StpAPPUserUtil.getTokenInfo());
        APPLoginUserInfo info = new APPLoginUserInfo();
        PeopleDto rpcById = levelOneServerInterface.getRpcById(appUser.getFkId());
        if (rpcById != null) {
            info.setTradeAreaId(rpcById.getTradeAreaId());
            info.setTradeAreaName(rpcById.getTradeAreaName());
        }
        info.setLoginId(appUser.getId());
        info.setLoginName(appUser.getName());
        info.setFk(appUser.getFkId());
        info.setUserType(appUser.getUserType());
        StpAPPUserUtil.cacheAPPLoginInfo(info);
        return AjaxJson.getSuccessData(map);
    }

    /**
     * 根据人脸ID查找数据库
     *
     * @param faceId
     * @return
     */
    private AppUser findByFaceId(String faceId) {
        QueryWrapper<AppUser> ew = new QueryWrapper<>();
        ew.lambda().eq(AppUser::getFaceId, faceId);
        List<AppUser> list = list(ew);
        return list.isEmpty() ? null : list.get(0);
    }

    public void changeBindShopStatus(BindShopDTO bindShopDTO) {
        log.info("修改商铺绑定状态:{}", JSONUtil.toJsonStr(bindShopDTO));
        StrUtil.split(bindShopDTO.getIds(), ",").forEach(id -> {
            appUserMapper.changeBindShopStatus(id, bindShopDTO.getBindShop());
        });
    }

    public AppUserDto findUserByPhone(String phone) {
        AppUser appUser = findByPhone(phone);
        if (appUser == null) {
            return null;
        }
        AppUserDto appUserDto = new AppUserDto();
        BeanUtils.copyProperties(appUser, appUserDto);
        return appUserDto;
    }

    /**
     * 修改手机并且修改密码
     *
     * @param updateAccountDTO
     * @return
     */
    public int updateAccount(UpdateAccountDTO updateAccountDTO) {
        Long id = updateAccountDTO.getId();
        AppUser appUser = this.getById(id);
        if (appUser == null) {
            return 0;
        }
        String phone = updateAccountDTO.getPhone();
        appUser.setId(id);
        appUser.setUpdateTime(new Date()).setPhone(phone);
        appUser.setPassword(passwordEncoder.encode(phone));
        return updateById(appUser) ? 1 : 0;
    }

    public AjaxJson purchaserLogin(LoginDto dto) {
        String phone = dto.getPhone();
        if (StrUtil.isEmpty(phone)) {
            return AjaxJson.getError("手机号不正确");
        }
        String pwd = dto.getPassword();
        if (StrUtil.isEmpty(pwd)) {
            return AjaxJson.getError("请输入密码");
        }
        AppUser appUser = findByPhone(phone);
        if (appUser == null || !Objects.equals(appUser.getUserType(), UserType.USER_TYPE_PURCHASER.getCode())) {
            return AjaxJson.getError("账号不存在");
        }
        if (!passwordEncoder.matches(pwd, appUser.getPassword())) {
            return AjaxJson.getError("密码不正确");
        }
        if (appUser.getStatus().equals("0")) {
            return AjaxJson.getError("该账户 " + appUser.getPhone() + " 已停用!");
        }
        PurchaserDto purchaserDto = FeignFactory.levelTwoServerInterface.getByPurchaserId(appUser.getFkId());
        if (purchaserDto == null) {
            return AjaxJson.getError("商户不存在或未认证");
        }
        if (purchaserDto.getJudgeStatus() == 0) {
            return AjaxJson.getError("商户未审核");
        }
        //开始执行登录
        StpAPPUserUtil.login(appUser.getId());
        APPLoginUserInfo info = new APPLoginUserInfo();
        info.setLoginId(appUser.getId());
        info.setLoginName(appUser.getName());
        info.setFk(appUser.getFkId());
        info.setUserType(appUser.getUserType());
        StpAPPUserUtil.cacheAPPLoginInfo(info);
        SoMap map = new SoMap();
        map.put("tokenInfo", StpAPPUserUtil.getTokenInfo());
        SoMap companyInfo = new SoMap();
        companyInfo.put("companyId", purchaserDto.getId());
        companyInfo.put("companyName", purchaserDto.getBusinessName());
        companyInfo.put("name", purchaserDto.getName());
        map.put("companyInfo", companyInfo);
        return AjaxJson.getSuccessData(map);
    }

    public boolean bindFkId(Long appUserId, Long fkId) {
        AppUser appUser = this.getById(appUserId);
        if (appUser == null) {
            return false;
        }
        appUser.setFkId(fkId);
        return this.updateById(appUser);
    }

    public void cleanFace(String faceId) {
        faceFactory.handler().deletePerson(faceId);
        appUserMapper.cleanFace(faceId);
    }
}
