package com.sptg.permissions.biz.service.impl;

import com.baomidou.mybatisplus.enums.SqlLike;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.plugins.Page;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.toolkit.IdWorker;
import com.sptg.common.core.beans.PageBean;
import com.sptg.common.core.beans.ResultBean;
import com.sptg.common.core.beans.ResultEnum;
import com.sptg.common.core.constant.CommonConstant;
import com.sptg.common.core.constant.OperationConstant;
import com.sptg.common.core.util.CommonUtil;
import com.sptg.common.core.util.JsonUtils;
import com.sptg.permissions.api.dto.AccountDto;
import com.sptg.permissions.api.dto.OrgDto;
import com.sptg.permissions.api.entity.Account;
import com.sptg.permissions.api.entity.Organization;
import com.sptg.permissions.api.entity.Role;
import com.sptg.permissions.biz.mapper.AccountMapper;
import com.sptg.permissions.biz.service.*;
import com.sptg.permissions.biz.stream.AccountDisableProduceInterface;
import com.sptg.permissions.biz.stream.SyncAccountProduceInterface;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * title: AccountServiceImpl
 * package: com.sptg.permissions.biz.security.impl
 * description: 账号-服务层接口实现类
 *
 *                  
 *                 
 */
@Service
@RequiredArgsConstructor
public class AccountServiceImpl extends ServiceImpl<AccountMapper, Account> implements AccountServiceInterface {

    /**
     * 账号缓存名称
     */
    private final static String ACCOUNT_CACHE_NAME = "sptg:permissions:account";

    private final RedisTemplate<String,String> redisTemplate;
    private final OrgServiceInterface orgServiceInterface;
    private final RoleServiceInterface roleServiceInterface;
    private final AccountRoleServiceInterface accountRoleServiceInterface;
    private final SyncAccountProduceInterface syncAccountProduceInterface;
    private final AccountDisableProduceInterface accountDisableProduceInterface;

    /* ------------------------------------- 重写父类查询方法，过滤已删除的数据 ------------------------------------- */
    /* -------------------------------------------------------------------------------------------------------------- */

    @Override
    public Account selectOne(Wrapper<Account> wrapper) {
        wrapper.notIn("i_status",OperationConstant.MINUS_ONE);
        return super.selectOne(wrapper);
    }

    @Override
    public List<Account> selectList(Wrapper<Account> wrapper) {
        wrapper.notIn("i_status",OperationConstant.MINUS_ONE);
        return super.selectList(wrapper);
    }

    @Override
    public Account selectById(Serializable id) {
        Wrapper<Account> wrapper = new EntityWrapper<>();
        wrapper.eq("l_id",id);
        return this.selectOne(wrapper);
    }

    @Override
    public Page<Account> selectPage(Page<Account> page, Wrapper<Account> wrapper) {
        wrapper.notIn("i_status",OperationConstant.MINUS_ONE);
        return super.selectPage(page, wrapper);
    }

    @Override
    public boolean updateBatch(List<Account> entityList) {
        boolean result = super.updateBatchById(entityList);
        if (result) {
            HashOperations<String, String, String> hashOperations = this.redisTemplate.opsForHash();
            //  删除缓存
            entityList.forEach(entity -> hashOperations.delete(ACCOUNT_CACHE_NAME,entity.getLoginName()));
            //  通知队列同步在线账号信息
            entityList.forEach(account -> {
                Message<Long> build = MessageBuilder.withPayload(account.getId()).build();
                this.syncAccountProduceInterface.output().send(build);
            });
        }
        return result;
    }

    @Override
    public boolean updateById(Account entity) {
        boolean result = super.updateById(entity);
        if (result){
            this.redisTemplate.opsForHash().delete(ACCOUNT_CACHE_NAME,entity.getLoginName());
        }
        return result;
    }

    /* -------------------------------------------------- 业务代码 -------------------------------------------------- */
    /* -------------------------------------------------------------------------------------------------------------- */

    @Override
    public Account selectByLoginName(String loginName) {
        //  查询缓存
        HashOperations<String, String, String> hashOperations = this.redisTemplate.opsForHash();
        String json = hashOperations.get(ACCOUNT_CACHE_NAME, loginName);
        if (StringUtils.isEmpty(json)){
            //  查询数据库
            Wrapper<Account> wrapper = new EntityWrapper<>();
            wrapper.eq("s_login_name",loginName);
            Account account = this.selectOne(wrapper);
            if (null != account){
                //  保存到缓存
                json = JsonUtils.objectToJson(account);
                hashOperations.put(ACCOUNT_CACHE_NAME,loginName,json);
            }
            return account;
        }
        return JsonUtils.jsonToPojo(json,Account.class);
    }

    @Override
    public Page<Account> pagingQueryByNotHaveRole(PageBean<Account,AccountDto> pageBean) {
        AccountDto dto = pageBean.getDto();
        if (null == dto.getSelectedId()){
            dto.setSelectedId(dto.getOnLineUser().getOrgId());
        }
        //  获取机构信息
        Organization organization = this.orgServiceInterface.selectById(dto.getSelectedId());
        if (null == organization){
            return pageBean;
        }
        //  获取子机构列表
        OrgDto orgDto = new OrgDto();
        orgDto.setExcludeOwn(OperationConstant.TWO);
        orgDto.setPosition(organization.getPosition());
        List<Organization> orgList = this.orgServiceInterface.selecSubList(orgDto);
        dto.setOrgList(orgList);
        //  获取分页对象
        pageBean.setRecords(this.baseMapper.selectAccountListByNotHaveRole(dto,pageBean));
        //  隐藏密码
        pageBean.getRecords().forEach(account -> account.setLoginPwd(CommonConstant.HIDE));
        return pageBean;
    }

    @Override
    public Page<Account> pagingQuery(PageBean<Account,AccountDto> pageBean) {
        AccountDto dto = pageBean.getDto();
        //  构建查询对象
        Wrapper<Account> wrapper = new EntityWrapper<>();
        Account onLineUser = dto.getOnLineUser();
        //过滤掉自己
        wrapper.notIn("l_id", onLineUser.getId());

        //  判断是否选中机构
        if (null != dto.getSelectedId()){
            Organization selectedOrg = this.orgServiceInterface.selectById(dto.getSelectedId());
            if (null == selectedOrg){
                return pageBean;
            }else{
                if (selectedOrg.getOrgType() == OperationConstant.THREE){

                }
            }
            wrapper.like("s_org_position",selectedOrg.getPosition(), SqlLike.RIGHT);
        }

        if (StringUtils.isEmpty(dto.getOrgPosition())){
            wrapper.like("s_estate_position", dto.getEstatePosition(), SqlLike.RIGHT);
        }

        if (StringUtils.isEmpty(dto.getOrgPosition())){
            wrapper.like("s_org_position", dto.getOrgPosition(), SqlLike.RIGHT);
        }
        //  判断是否以登录名为条件
        if (!StringUtils.isEmpty(dto.getLoginName())){
            wrapper.like("s_login_name",dto.getLoginName(), SqlLike.RIGHT);
        }
        //  判断是否以用户姓名为条件
        if (!StringUtils.isEmpty(dto.getUserName())){
            wrapper.like("s_user_name",dto.getUserName(), SqlLike.RIGHT);
        }
        //  判断是否以联系方式为条件
        if (!StringUtils.isEmpty(dto.getUserMobile())){
            wrapper.like("s_user_mobile",dto.getUserMobile(), SqlLike.RIGHT);
        }
        wrapper.notIn("l_id",1);
        //  判断是否以登陆状态作为条件
        if (null != dto.getIsEnable()){
            wrapper.eq("i_is_enable",dto.getIsEnable());
        }
        //  数据过滤，只查询用户所属机构和子机构下的用户信息
        wrapper.like("s_org_position",dto.getOrgPosition(), SqlLike.RIGHT);
        // 排序
        if (dto.getSortField() != null && dto.getSortOrder() != null){
            wrapper.orderBy(dto.getSortField(),dto.getSortOrder().equals("asc"));
        }else {
        //  排序字段 时间降序
            wrapper.orderBy("t_create_date",false);
        }
        Page<Account> page = this.selectPage(pageBean, wrapper);

        Long roleId = dto.getRoleId();
        List<Account> records = page.getRecords();
        List<Account> list = new ArrayList<>();

        //  获取用户角色信息
        records.forEach(account -> {
            //  获取账号所拥有的角色列表
            List<Role> roleList = this.roleServiceInterface.getListByAccountId(account.getId());
            boolean flag = false;
            if (roleId != null){
                for (int i = 0; i < roleList.size(); i++) {
                    Role role = roleList.get(i);
                    if (roleId != null && role.getId().equals(roleId)){
                        flag = true;
                        break;
                    }
                }
            }else{
                flag = true;
            }
            if (flag){
                account.setRoleList(roleList);
                //  隐藏密码
                account.setLoginPwd(CommonConstant.HIDE);
                //  隐藏菜单信息
                account.setMenuList(null);
                list.add(account);
            }
        });
        page.setRecords(list);
        return page;
    }

    @Override
    @Transactional(rollbackFor = Throwable.class)
    public ResultBean<Account> addEntity(AccountDto dto) {
        Account onLineUser = dto.getOnLineUser();
        //  创建人
        dto.setCreateAccountId(onLineUser.getId());
        //  创建时间
        dto.setCreateDate(new Date());
        //  登陆密码加密
        if (null == dto.getIsNotEncryption() || dto.getIsNotEncryption() != 1) {
            dto.setLoginPwd(this.passwordEncrypt(dto.getLoginPwd()));
        }
        //  生成唯一Id
        dto.setId(IdWorker.getId());
        //  保存用户
        if (this.insert(dto)){
            //  判断是否需要绑定角色
            if (!StringUtils.isEmpty(dto.getRoleIds())){
                this.accountRoleServiceInterface.batchInsertByAccount(dto);
            }
            dto.setLoginPwd(CommonConstant.HIDE);
            return new ResultBean<>(ResultEnum.SUCCESS,dto);
        }
        return new ResultBean<>(ResultEnum.ERROR);
    }

    @Override
    @Transactional(rollbackFor = Throwable.class)
    public ResultBean<Boolean> updateEntity(AccountDto dto) {
        //  判断是否修改了密码
        if (null != dto.getLoginPwd() && !CommonConstant.HIDE.equals(dto.getLoginPwd())){
            //  登陆密码加密
            dto.setLoginPwd(this.passwordEncrypt(dto.getLoginPwd()));
        }else {
            dto.setLoginPwd(null);
        }
        //  保存修改
        if (this.updateById(dto)){
            if (null != dto.getRoleIds()) {
                //  判断是否需要修改绑定角色
                this.accountRoleServiceInterface.batchInsertOrUpdateByAccount(dto);
            }
            return new ResultBean<>(ResultEnum.SUCCESS,true);
        }
        return new ResultBean<>(ResultEnum.ERROR);
    }

    @Override
    @Transactional(rollbackFor = Throwable.class)
    public ResultBean<Boolean> deleteEntity(AccountDto dto) {
        //  最高级的账号不能被删除
        if (dto.getId() == OperationConstant.ONE){
            return new ResultBean<>(ResultEnum.FORBIDDEN);
        }
        //  获取账号信息
        Account dbAccount = this.selectById(dto.getId());
        Assert.notNull(dbAccount,"账号不存在,请核实后重新操作");
        //不能删除admin账户
        if(dbAccount.getId()==OperationConstant.ONE){
            return new ResultBean<>(ResultEnum.FORBIDDEN);
        }
        //  标记为删除状态
        dbAccount.setStatus(OperationConstant.MINUS_ONE);
        //  标记为不可用状态
        dbAccount.setIsEnable(OperationConstant.TWO);
        if (this.updateById(dbAccount)){
            //  删除此账号下的所有角色关联
            this.accountRoleServiceInterface.clearAccountRole(dbAccount.getId());
            //  通知队列将账号强制下线
            Message<Long> build = MessageBuilder.withPayload(dto.getId()).build();
            this.accountDisableProduceInterface.output().send(build);
            return new ResultBean<>(ResultEnum.SUCCESS,true);
        }
        return new ResultBean<>(ResultEnum.ERROR);
    }

    @Override
    @Transactional(rollbackFor = Throwable.class)
    public ResultBean<Boolean> deleteAccountList(AccountDto dto){
        List<String> ids = dto.getIds();
        for(String id : ids){
            //  获取账号信息
            Account dbAccount = this.selectById(Long.valueOf(id));
            Assert.notNull(dbAccount,"账号不存在,请核实后重新操作");
            //不能删除admin账户
            if(dbAccount.getId()==OperationConstant.ONE){
                return new ResultBean<>(ResultEnum.FORBIDDEN);
            }
            //  标记为删除状态
            dbAccount.setStatus(OperationConstant.MINUS_ONE);
            //  标记为不可用状态
            dbAccount.setIsEnable(OperationConstant.TWO);
            if (this.updateById(dbAccount)){
                //  删除此账号下的所有角色关联
                this.accountRoleServiceInterface.clearAccountRole(dbAccount.getId());
                //  通知队列将账号强制下线
                Message<Long> build = MessageBuilder.withPayload(dbAccount.getId()).build();
                this.accountDisableProduceInterface.output().send(build);
            }
        }
        return new ResultBean<>(ResultEnum.SUCCESS,true);
    }

    @Override
    public ResultBean<Boolean> untiedWeChat(AccountDto dto) {
        //修改成功
        if(this.baseMapper.untiedWeChat(dto.getId())>=1){
            //  通知队列同步在线账号信息
            Message<Long> build = MessageBuilder.withPayload(dto.getId()).build();
            this.syncAccountProduceInterface.output().send(build);
            //删除redis中account信息
            this.redisTemplate.opsForHash().delete(ACCOUNT_CACHE_NAME,dto.getLoginName());
            return new ResultBean<>(ResultEnum.SUCCESS,true);
        }
        return new ResultBean<>(ResultEnum.ERROR);
    }

    @Override
    public ResultBean<Boolean> bindOpenid(AccountDto dto) {
        Account account = new Account();
        account.setId(dto.getId());
        account.setOpenid(dto.getOpenid());
        //  保存修改
        if (super.updateById(account)){
            //  通知队列同步在线账号信息
            Message<Long> build = MessageBuilder.withPayload(dto.getId()).build();
            this.syncAccountProduceInterface.output().send(build);
            //删除redis中account信息
            this.redisTemplate.opsForHash().delete(ACCOUNT_CACHE_NAME,dto.getLoginName());
            return new ResultBean<>(ResultEnum.SUCCESS,true);
        }
        return new ResultBean<>(ResultEnum.ERROR);
    }

    @Override
    public Page<Account> page(PageBean<Account, AccountDto> pageBean) {
        AccountDto dto = pageBean.getDto();
        if (null == dto.getSelectedId()){
            dto.setSelectedId(dto.getOnLineUser().getOrgId());
        }
        //  获取机构信息
        Organization organization = this.orgServiceInterface.selectById(dto.getSelectedId());
        if (null == organization){
            return pageBean;
        }
        //  获取子机构列表
        OrgDto orgDto = new OrgDto();
        orgDto.setExcludeOwn(OperationConstant.TWO);
        orgDto.setPosition(organization.getPosition());
        List<Organization> orgList = this.orgServiceInterface.selecSubList(orgDto);
        dto.setOrgList(orgList);
        //  获取分页对象
        pageBean.setRecords(this.baseMapper.selectAccountListByHaveRole(dto,pageBean));
        //
        List<Account> list = new ArrayList<>();
        pageBean.getRecords().forEach(account -> {
            if (!account.getId().equals(dto.getOnLineUser().getId())){
                //  获取账号所拥有的角色列表
                List<Role> roleList = this.roleServiceInterface.getListByAccountId(account.getId());
                account.setRoleList(roleList);
                //  隐藏密码
                account.setLoginPwd(CommonConstant.HIDE);
                //  隐藏菜单信息
                account.setMenuList(null);
                list.add(account);
            }
        });
        pageBean.setRecords(list);
        return pageBean;
    }

    @Override
    public ResultBean<String> resetPassword(Account dto) {
        // 生成随机密码 8位，包含数字和字母
        String randomPassword = CommonUtil.getRandomPassword(8);
        //  登陆密码加密
        dto.setLoginPwd(this.passwordEncrypt(randomPassword));
        dto.setHadUpdatePwd(0);
        if (this.updateById(dto)){
            return new ResultBean<>(ResultEnum.SUCCESS, randomPassword);
        }
        return new ResultBean<>(ResultEnum.ERROR);
    }

    @Override
    public ResultBean<Boolean> modifyPassword(Account account) {
        account.setLoginPwd(this.passwordEncrypt(account.getLoginPwd()));
        account.setHadUpdatePwd(1);
        if (this.updateById(account)){
            //  通知队列同步在线账号信息
            Message<Long> build = MessageBuilder.withPayload(account.getId()).build();
            this.syncAccountProduceInterface.output().send(build);
            //删除redis中account信息
            String tokenKey = "on-line:user:" + account.getLoginToken();
//            String s = this.redisTemplate.opsForValue().get(tokenKey);
            this.redisTemplate.delete(tokenKey);
            return new ResultBean<>(ResultEnum.SUCCESS);
        }
        return new ResultBean<>(ResultEnum.ERROR);
    }

    @Override
    public Account getByUserMobile(String mobile) {
        Assert.hasText(mobile, "手机号必传");
        Wrapper<Account> wrapper = new EntityWrapper<>();
        wrapper.eq("s_user_mobile", mobile);
        Account account = this.selectOne(wrapper);
        return account;
    }


}
