package com.pj.project.app_user;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;

import cn.dev33.satoken.spring.SpringMVCUtil;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.json.JSONUtil;
import cn.hutool.log.StaticLog;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.pj.api.client.admin.AdminInterface;
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.dto.*;
import com.pj.common.core.exception.ServiceException;
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.Status;
import com.pj.project.app_user.dto.ForgetPasswordDto;
import com.pj.project.app_user.dto.LoginDto;
import com.pj.project.app_user.dto.RegisterDto;
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.retry.SmsRetryService;
import com.pj.utils.cache.RedisUtil;
import com.pj.utils.sg.AjaxJson;
import com.pj.utils.sg.WebNbUtil;
import com.pj.utils.so.SoMap;
import org.apache.commons.lang3.StringUtils;
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 com.baomidou.mybatisplus.extension.service.IService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.transaction.annotation.Transactional;


/**
 * Service: app_user -- 移动端账号
 *
 * @author qzy
 */
@Service
@Transactional(rollbackFor = Exception.class)
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 SmsRetryService smsRetryService;
    @Autowired
    private LevelOneServerInterface levelOneServerInterface;
    @Autowired
    private TransportInterface transportInterface;
    @Autowired
    AppUserLoginLogService appUserLoginLogService;

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


    /**
     * 增
     */
    void add(AppUser t) {
        save(t);
    }

    /**
     * 删
     */
    void delete(Long id) {
        removeById(id);
    }

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

    }

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

    /**
     * 个人中心-个人详细信息
     *
     * @return
     */
    AppUserVo getSelfInfo() {
        //查询当前人
        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;
    }

    /**
     * 查集合 - 根据条件（参数为空时代表忽略指定条件）
     */
    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;
        //手机号去重
        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().toString().equals(smsCode)) throw new SecurityException("验证码输入错误,请检查!");
        //4.开始新增
        AppUser appUser = new AppUser();
        //手机号
        appUser.setPhone(phone);
        //注册身份
        appUser.setUserType(registerDto.getType());
        //加密并设置登陆密码
        String password = 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) {
        //登陆日志信息
        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);
        //比对密码
        String userPassword = appUser.getPassword();
        boolean matches = passwordEncoder.matches(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) throws Exception {
        //生成4位随机数
        Random random = new Random();
        int randomNumber = random.nextInt(9000) + 1000;
        //保存到缓存,默认1分钟 todo:届时放开手机验证码 randomNumber
        RedisUtil.setByMINUTES(PREFIX + phone, 123 + "", 1);
        //发送验证码短信
        return true;

    }


    /**
     * 更换角色
     */
    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);
    }

    /**
     * 退出登录
     *
     * @param appUserId appUser表主键
     * @return
     */
    public String logout(Object appUserId) {
        if (appUserId == null || appUserId.toString().trim().equals(""))
            throw new ServiceException("退出信息异常!");
        StpAPPUserUtil.logout(appUserId);
        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 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;
    }

    /**
     * 远程调用: 当从航通导入数据时,自动给边民生成账号
     */
    public boolean generatePeopleAccount(PeopleDto peopleDto) throws Exception {
        //检查是否重复注册
        List<AppUser> appUsers = appUserMapper.selectList(new LambdaQueryWrapper<AppUser>().eq(AppUser::getPhone, peopleDto.getBorderTel()));
        if (appUsers.size() != 0)
            throw new ServiceException("\n该用户已注册! phone = " + peopleDto.getBorderTel() + "\n");
        //创建保存对象
        AppUser appUser = new AppUser();
        //设置基本属性
        appUser.setAuth(1 + ""); // 默认已认证
        appUser.setUserType(1); // 用户类型 1
        appUser.setCreateTime(new Date()); // 创建时间
        appUser.setPhone(peopleDto.getBorderTel()); // 电话
        appUser.setStatus("1"); // 可用状态
        appUser.setDeleteStatus(DeleteStatus.DELETE_STATUS_ON.getCode()); // 默认可用
        appUser.setAuthTime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())); // 认证时间
        appUser.setName(peopleDto.getBorderName()); // 昵称
        appUser.setFkId(peopleDto.getId()); // 外键
        appUser.setCreateUnit("航通");
        //随机生成6位数密码
        int password = (int) (Math.random() * (999999 - 100000 + 1) + 100000);
        //密码加密
        String encodePassword = passwordEncoder.encode(password + "");
        //设置密码
        appUser.setPassword(encodePassword);
        //保存
        int insert = appUserMapper.insert(appUser);
        //发送短信
        if (insert == 1) {
            //todo: 届时放开注释
//			boolean msg = smsRetryService.sendSmsRegisteMsg(null, "您好,您已成功注册[边民互市]app账号。账号:" + peopleDto.getBorderTel() + ", 初始密码:" + password + "。可前往app进行修改");
//			return msg;
            System.out.println("注册成功! 账户 = " + peopleDto.getBorderTel() + " password = " + password);
            return true;
        }
        throw new RuntimeException("同步航通信息时,边民注册app信息失败,边民手机号为: " + peopleDto.getBorderTel() + "。 时间: " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
    }

    /**
     * 远程调用: 当从航通导入数据时,自动给外籍商户生成账号
     */
    public int generateEnterpriseAccount(EnterpriseDto enterpriseDto) throws Exception {
        //判断是否已被注册
        List<AppUser> appUsers = appUserMapper.selectList(new LambdaQueryWrapper<AppUser>().eq(AppUser::getPhone, enterpriseDto.getOwnerTel()));
        if (appUsers.size() != 0) {
            StaticLog.error("用户手机号已被注册：{},{}", enterpriseDto.getOwnerTel(), JSONUtil.toJsonStr(enterpriseDto));
            return 0;
        }
        //创建保存对象
        AppUser appUser = new AppUser();
        //设置基本属性
        appUser.setAuth(1 + ""); // 默认已认证
        appUser.setUserType(5); // 用户类型 1
        appUser.setCreateTime(new Date()); // 创建时间
        appUser.setPhone(enterpriseDto.getOwnerTel()); // 电话
        appUser.setStatus(Status.STATUS_ONE.getCode() + ""); // 可用状态
        appUser.setDeleteStatus(DeleteStatus.DELETE_STATUS_ON.getCode()); // 默认可用
        appUser.setAuthTime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())); // 认证时间
        appUser.setName(enterpriseDto.getOwnerName()); // 昵称
        appUser.setFkId(enterpriseDto.getId()); // 外键
        appUser.setCreateUnit("航通"); // 创建单位
        //随机生成6位数密码
        //int password = (int) (Math.random() * (999999 - 100000 + 1) + 100000);
        String password = appUser.getPhone();
        //密码加密
        String encodePassword = passwordEncoder.encode(password + "");
        //设置密码
        appUser.setPassword(encodePassword);
        //保存
        int insert = appUserMapper.insert(appUser);
        //发送短信
        if (insert == 1) {
            //查询外籍商户和商铺是否存在,不存在则删除app user信息 ownTel
//			List<ShopDto> shopDtoListByPhone = levelOneServerInterface.getShopDtoListByPhone(appUser.getPhone());
//			List<EnterpriseDto> enterpriseDtoListByPhone = levelOneServerInterface.getEnterpriseDtoListByPhone(appUser.getPhone());
//			if(shopDtoListByPhone.size() != 1 && enterpriseDtoListByPhone.size() != 1)
//				throw new ServiceException("当航通同步商铺信息时,商铺或者外籍商户信息入库发生异常,故在自动创建appUser时抛出异常回滚数据。");
            //todo: 届时放开注释
//			boolean msg = smsRetryService.sendSmsRegisteMsg(null, "您好,您已成功注册[边民互市]app账号。账号:" + peopleDto.getBorderTel() + ", 初始密码:" + password + "。可前往app进行修改");
//			return msg;
            System.out.println("\n注册成功! 账户 = " + enterpriseDto.getOwnerTel() + " password = " + password + "\n");
            return 1;
        }
        StaticLog.error("同步航通信息时,边民注册app信息失败,边民手机号为: " + enterpriseDto.getOwnerTel() + "。 时间: " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
        return 1;
    }


}
