/**
 * 文件：UserServiceImpl.java
 * 版本：1.0.0
 * 日期：
 * Copyright &reg;
 * All right reserved.
 */

package com.mortals.xhx.base.system.user.service.impl;

import cn.hutool.core.util.PhoneUtil;
import cn.hutool.core.util.RandomUtil;
import com.alibaba.fastjson.JSONObject;
import com.mortals.framework.ap.SysConstains;
import com.mortals.framework.common.code.UserType;
import com.mortals.framework.exception.AppException;
import com.mortals.framework.model.Context;
import com.mortals.framework.model.PageInfo;
import com.mortals.framework.model.Result;
import com.mortals.framework.service.IUser;
import com.mortals.framework.service.impl.AbstractCRUDCacheServiceImpl;
import com.mortals.framework.util.HttpUtil;
import com.mortals.framework.util.SecurityUtil;
import com.mortals.framework.util.StringUtils;
import com.mortals.xhx.base.system.menu.model.MenuEntity;
import com.mortals.xhx.base.system.menu.service.MenuService;
import com.mortals.xhx.base.system.resource.model.ResourceEntity;
import com.mortals.xhx.base.system.resource.service.ResourceService;
import com.mortals.xhx.base.system.role.dao.RoleUserDao;
import com.mortals.xhx.base.system.role.model.RoleUserEntity;
import com.mortals.xhx.base.system.role.model.RoleUserQuery;
import com.mortals.xhx.base.system.user.dao.UserDao;
import com.mortals.xhx.base.system.user.model.UserEntity;
import com.mortals.xhx.base.system.user.model.UserQuery;
import com.mortals.xhx.base.system.user.service.UserService;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>Title: 用户信息</p>
 * <p>Description: UserServiceImpl service接口 </p>
 * <p>Copyright: Copyright &reg;  </p>
 * <p>Company: </p>
 *
 * @author
 * @version 1.0.0
 */
@Service("userService")
public class UserServiceImpl extends AbstractCRUDCacheServiceImpl<UserDao, UserEntity, Long> implements UserService {


    @Autowired
    private MenuService menuService;
    @Autowired
    private ResourceService resourceService;
    @Autowired
    private RoleUserDao roleUserDao;

    @Value("${sms.smsSendUrl:http://sms.wx3.com.cn/api/index/index}")
    private String smsApiUrl;
    @Value("${sms.apiId:ADsUXLrS81vZDU95}")
    private String appid;

    /**
     * 短信模板ID
     **/
    private static String SMS_TPYE = "30";

    private static String SMS_VERIFY_CODE_KEY = "login:sms:verify:";

    @Override
    protected String getExtKey(UserEntity data) {
        return data.getLoginName();
    }


    public void doHandlerUser(UserEntity entity) throws AppException {
        if (StringUtils.isNotEmpty(entity.getLoginPwd())) {
            try {
                entity.setLoginPwd(SecurityUtil.md5DoubleEncoding(entity.getLoginPwd()));
            } catch (Exception e) {
                throw new AppException("密码转换异常");
            }
        } else {
            entity.setLoginPwd(null);
        }
//        if (entity.isSystemUser()) {
//            entity.setUserType(UserType.SYSTEM.getValue());
//        } else {
//            entity.setUserType(UserType.CUSTOMER.getValue());
//        }
    }

    @Override
    protected void saveBefore(UserEntity entity, Context context) throws AppException {
        this.doHandlerUser(entity);
    }

    @Override
    protected void saveAfter(UserEntity entity, Context context) throws AppException {
        if (CollectionUtils.isNotEmpty(entity.getRoleIds())) {
            List<RoleUserEntity> roleUserEntityList = new ArrayList<>();
            entity.getRoleIds().stream().forEach(item -> {
                RoleUserEntity roleUserEntity = new RoleUserEntity();
                roleUserEntity.setUserId(entity.getId());
                roleUserEntity.setRoleId(item);
                roleUserEntityList.add(roleUserEntity);
            });
            roleUserDao.insertBatch(roleUserEntityList);
        }
    }

    @Override
    protected void updateBefore(UserEntity entity, Context context) throws AppException {
/*        if (entity.getId().longValue() == SysConstains.ADMIN_ID && !context.getUser().isAdmin()) {
            throw new AppException("你没有权限执行该操作");
        }*/
        if (entity.getId().longValue() == SysConstains.ADMIN_ID) {
            throw new AppException("你没有权限执行该操作");
        }
        this.doHandlerUser(entity);
    }

    @Override
    protected void updateAfter(UserEntity entity, Context context) throws AppException {
        if (CollectionUtils.isNotEmpty(entity.getRoleIds())) {
            List<RoleUserEntity> roleUserEntityList = new ArrayList<>();
            entity.getRoleIds().stream().forEach(item -> {
                RoleUserEntity roleUserEntity = new RoleUserEntity();
                roleUserEntity.setUserId(entity.getId());
                roleUserEntity.setRoleId(item);
                roleUserEntityList.add(roleUserEntity);
            });
            RoleUserEntity condition = new RoleUserEntity();
            condition.setUserId(entity.getId());
            roleUserDao.delete(condition);
            roleUserDao.insertBatch(roleUserEntityList);
        }
    }

    @Override
    protected UserEntity findBefore(UserEntity params, Context context) throws AppException {
//        if (StringUtils.isNotEmpty(params.getDeptIds())) {
//            params.setDeptIds(StringUtils.fillWithMark(params.getDeptIds(), ","));
//        }
        return super.findBefore(params, context);
    }

    @Override
    protected UserEntity findBefore(UserEntity params, PageInfo pageInfo, Context context) throws AppException {
//        if (StringUtils.isNotEmpty(params.getDeptIds())) {
//            params.setDeptIds(StringUtils.fillWithMark(params.getDeptIds(), ","));
//        }
        return super.findBefore(params, pageInfo, context);
    }

    @Override
    protected void findAfter(UserEntity params, PageInfo pageInfo, Context context, List<UserEntity> list) throws AppException {
        if (CollectionUtils.isNotEmpty(list)) {
            list.stream().forEach(item -> {
                RoleUserEntity query = new RoleUserEntity();
                query.setUserId(item.getId());
                List<RoleUserEntity> roleUserEntityList = roleUserDao.getList(query);
                List<Long> roleIds = new ArrayList<>();
                roleUserEntityList.stream().forEach(role -> {
                    roleIds.add(role.getRoleId());
                });
                item.setRoleIds(roleIds);
                String roleIdStrs = StringUtils.join(roleIds, ",");
                item.setRoleIdStrs(roleIdStrs);
                RoleUserQuery roleUserQuery = new RoleUserQuery();
                roleUserQuery.setUserId(item.getId());


            });
        }
    }

    public UserEntity findByLoginName(String loginName) {
        UserQuery params = new UserQuery();
        params.setLoginName(loginName);
        List<UserEntity> userList = super.dao.getList(params);
        if (userList != null && userList.size() > 0) {
            return userList.get(0);
        }
        return null;
    }

    @Override
    public UserEntity doLogin(String loginName, String password, String loginIp) throws AppException {
        UserEntity sysUser = this.findByLoginName(loginName);
        if (sysUser == null || !sysUser.getLoginName().equals(loginName)) {
            throw new AppException("用户名不存在！");
        }
        try {
            if (!sysUser.getLoginPwd().equals(SecurityUtil.md5DoubleEncoding(password))) {
                throw new AppException("登录密码错误！");
            }
        } catch (Exception e) {
            throw new AppException("密码验认出错！", e);
        }
        UserEntity update = new UserEntity();
        update.setId(sysUser.getId());
        update.setLastLoginAddress(loginIp);
        update.setLastLoginTime(new Date());
        this.dao.update(update);
        return sysUser;
    }

    @Override
    public UserEntity doCheckUser(String loginName, String password) throws AppException {
        UserEntity sysUser = this.findByLoginName(loginName);
        if (sysUser == null || !sysUser.getLoginName().equals(loginName)) {
            return null;
        }
        try {
            if (!sysUser.getLoginPwd().equals(SecurityUtil.md5DoubleEncoding(password))) {
                return null;
            }
        } catch (Exception e) {
            return null;
        }
        return sysUser;
    }

    @Override
    public Set<Long> findAllAuthIds(UserEntity userEntity) throws AppException {
        Set<Long> authIds = new HashSet<Long>();
        if (userEntity.isAdmin()) {
            return authIds;
        }
        authIds.addAll(dao.getAuthListById(userEntity.getId()));
        return authIds;
    }

    @Override
    public List<MenuEntity> findOutlookBarList(IUser user) {
        Set<String> urls = new HashSet<String>();
        if (!user.isAdmin()) {
            List<ResourceEntity> resList = resourceService.findListByUserId(user.getId());
            for (ResourceEntity res : resList) {
                String url = res.getUrl();
                if (StringUtils.isEmpty(url)) {
                    continue;
                }
                url = url.replaceAll("，", ",");
                urls.addAll(StringUtils.converStr2Set(url));
            }
        }
        Set<Long> authIds = new HashSet<Long>();
        Map<Long, MenuEntity> menuMap = new HashMap<Long, MenuEntity>();
        List<MenuEntity> userModuleList = this.menuService.findAllEnable();
        for (MenuEntity sysModule : userModuleList) {
            if (sysModule == null) {
                continue;
            }
            menuMap.put(sysModule.getId(), sysModule);
            if (!user.isAdmin() && urls.contains(StringUtils.trim(sysModule.getUrl()))) {
                authIds.add(sysModule.getId());
            }
        }
        if (!user.isAdmin()) {
            Long[] ids = authIds.toArray(new Long[authIds.size()]);
            for (Long id : ids) {
                MenuEntity menu = menuMap.get(id);
                while (menu != null) {
                    authIds.add(menu.getId());
                    menu = menuMap.get(menu.getParentId());
                }
            }
        }
        List<MenuEntity> outlookBar = new ArrayList<MenuEntity>();
        List<MenuEntity> norightList = new ArrayList<MenuEntity>();
        for (MenuEntity sysModule : userModuleList) {
            if (!user.isAdmin() && !authIds.contains(sysModule.getId())) {
                norightList.add(sysModule);
                continue;
            }
            if (sysModule.getParentId() == null || sysModule.getParentId().longValue() == 0) {
                outlookBar.add(sysModule);
                continue;
            }
            MenuEntity sysModuleParent = menuMap.get(sysModule.getParentId());
            if (sysModuleParent != null) {
                sysModuleParent.getChildList().add(sysModule);
            }
        }
        return outlookBar;
    }

    @Override
    public Result<UserEntity> find(Long platformId, UserEntity params, int currPage, int prePageResult) throws AppException {
        PageInfo pageInfo = new PageInfo(prePageResult);
        pageInfo.setCurrPage(currPage);
        return super.find(params, pageInfo, null);
    }

    @Override
    public UserEntity createUser(IUser currUser, Long customerId, String customerName, String loginName, String password,
                                 String userName, String mobile) throws AppException {
        try {
            UserEntity entity = new UserEntity();
            entity.initAttrValue();
            entity.setLoginName(loginName);
            entity.setRealName(userName);
            entity.setCustomerId(customerId);
            entity.setLoginPwd(password);
            entity.setMobile(mobile);
            entity.setUserType(UserType.CUSTOMER.getValue());
            entity.setCreateTime(new Date());
            if (currUser != null) {
                entity.setCreateUser(currUser.getLoginName());
                entity.setCreateUserName(currUser.getRealName());
            }
            this.doHandlerUser(entity);
            dao.insert(entity);
            return entity;
        } catch (Exception e) {
            log.error("给客户创建用户异常-->customerId:" + customerId + ",customerName:" + customerName + ",loginName:" + loginName +
                    "-->原因：" + e.getMessage());
            return null;
        }
    }

    @Override
    public boolean existUser(String loginName, Long userId) throws AppException {
        UserEntity sysUser = this.findByLoginName(loginName);
        boolean bRet = false;
        if (sysUser != null) {
            if (userId == null || userId == 0 || userId.longValue() != sysUser.getId().longValue()) {
                bRet = true;
            }
        }
        return bRet;
    }

    @Override
    public boolean updateUserPwd(String loginName, String oldPwd, String newPwd) throws AppException {
        UserEntity sysUser = this.findByLoginName(loginName);
        if (sysUser == null || !sysUser.getLoginName().equals(loginName)) {
            throw new AppException("帐号错误！");
        }
        try {
            if (!sysUser.getLoginPwd().equals(SecurityUtil.md5DoubleEncoding(oldPwd))) {
                throw new AppException("原始密码错误！");
            }
        } catch (Exception e) {
            throw new AppException("密码验认出错！", e);
        }
        try {
            sysUser.setLoginPwd(SecurityUtil.md5DoubleEncoding(newPwd));

        } catch (Exception e) {
            throw new AppException("密码转换异常！", e);
        }
        dao.update(sysUser);
        return true;
    }

    @Override
    public UserDao getUserDao() {
        return this.getDao();
    }

    @Override
    public void sendSmsVerifyCode(String mobileNumber) throws AppException {
        if (StringUtils.isEmpty(mobileNumber)) {
            throw new AppException("手机号不能为空");
        }
        if (!PhoneUtil.isPhone(mobileNumber)) {
            throw new AppException("手机号码格式不正确");
        }
        UserEntity user = this.selectOne(new UserQuery().mobile(mobileNumber));
        if (user == null) {
            throw new AppException("手机号码:" + mobileNumber + "没有注册用户");
        }
        String verifyCode = cacheService.get(SMS_VERIFY_CODE_KEY + mobileNumber);
        if (StringUtils.isNotEmpty(verifyCode)) {
            throw new AppException("当前手机号码已发送验证码，请稍后重试");
        }
        try {
            Map<String, String> params = new HashMap<>();
            params.put("appid", appid);
            params.put("phone", mobileNumber);
            params.put("type", SMS_TPYE);

            String[] json = new String[2];
            String vCode = RandomUtil.randomNumbers(6);
            json[0] = vCode;
            json[1] = "1";
            params.put("json", JSONObject.toJSON(json).toString());
            String resp = HttpUtil.doPost(smsApiUrl, params);
            JSONObject respJson = JSONObject.parseObject(resp);
            if (respJson.getIntValue("code") == 0) {
                throw new AppException("短信发送失败:" + respJson.getString("message"));
            }
            //有效期60秒
            cacheService.setnx(SMS_VERIFY_CODE_KEY + mobileNumber, vCode, 60);
        } catch (Exception e) {
            log.error("短信发送异常", e);
            throw new AppException("短信发送异常");
        }
    }

    @Override
    public UserEntity doSmsLogin(String mobileNumber, String verifyCode, String loginIp) throws AppException {
        if (StringUtils.isEmpty(mobileNumber)) {
            throw new AppException("手机号不能为空");
        }
        if (StringUtils.isEmpty(verifyCode)) {
            throw new AppException("验证码不能为空");
        }
        if (!PhoneUtil.isPhone(mobileNumber)) {
            throw new AppException("手机号码格式不正确");
        }
        UserEntity customer = this.selectOne(new UserQuery().mobile(mobileNumber));
        if (customer == null) {
            throw new AppException("手机号码:" + mobileNumber + "没有注册用户");
        }
        String vCode = cacheService.get(SMS_VERIFY_CODE_KEY + mobileNumber);
        if (StringUtils.isEmpty(vCode)) {
            throw new AppException("验证码已失效");
        }
        if (!verifyCode.equals(vCode)) {
            throw new AppException("验证码不正确");
        }
        UserEntity update = new UserEntity();
        update.setId(customer.getId());
        update.setLastLoginAddress(loginIp);
        update.setLastLoginTime(new Date());
        this.update(update);
        return customer;
    }

}