package com.ssyf.module.auth.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ssyf.common.core.helper.DataPathHelper;
import com.ssyf.module.auth.domain.bo.MenuTreeBo;
import com.ssyf.module.auth.domain.entity.DataRelation;
import com.ssyf.module.auth.domain.entity.MenuPermission;
import com.ssyf.module.auth.domain.entity.RoleMenuPermissionRelation;
import com.ssyf.module.auth.domain.entity.UserRoleRelation;
import com.ssyf.module.auth.domain.query.DataRelationQuery;
import com.ssyf.module.auth.domain.query.MenuPermissionQuery;
import com.ssyf.module.auth.emuns.DataRelationEnum;
import com.ssyf.common.core.enums.StatusCommonEnum;
import com.ssyf.common.core.util.AssertUtil;
import com.ssyf.common.core.util.EntityUtil;
import com.ssyf.common.core.util.SimpleLockerUtil;
import com.ssyf.common.security.helper.ClientContextHelper;
import com.ssyf.common.security.domain.ClientInfo;
import com.ssyf.common.core.helper.DataPedigreeHelper;
import com.ssyf.module.auth.mapper.MenuPermissionMapper;
import com.ssyf.module.auth.service.*;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import com.ssyf.common.web.apicode.ApiCodeUser;
import com.ssyf.common.web.error.ServiceRuntimeException;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.ssyf.plugs.mysql.helper.MybatisPlusHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.locks.Lock;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author auth
 * @since 2022-12-12
 */
@Service
public class MenuPermissionServiceImpl extends ServiceImpl<MenuPermissionMapper, MenuPermission> implements MenuPermissionService {
    @Lazy
    @Autowired
    private RoleMenuPermissionRelationService roleMenuPermissionRelationService;

    @Lazy
    @Autowired
    private UserRoleRelationService userRoleRelationService;

    @Lazy
    @Autowired
    private UserPermissionRelationService userPermissionRelationService;

    @Lazy
    @Autowired
    private DataRelationService dataRelationService;

    @Override
    public MenuPermission addOne(MenuPermissionQuery query) {
        ClientInfo clientInfo = ClientContextHelper.getClientInfo();
        MenuPermission menu = BeanUtil.copyProperties(query, MenuPermission.class);
        menu.setUid(IdUtil.simpleUUID()).setCreatedTime(LocalDateTime.now());
        menu.setCreatorName(clientInfo.getNickname()).setCreatorId(clientInfo.getId().toString());
        if(StrUtil.isNotBlank(query.getParentId())) {
            Lock lock = SimpleLockerUtil.getLocker(query.getParentId() , MenuPermission.class.getSimpleName());
            lock.lock();
            try {
                //设置级联信息
                DataPedigreeHelper.initCascadeField(menu, query.getParentId(), this::getOneByUid, this::getLastFormNextChildrenByUid);
            }finally {
                lock.unlock();
            }
        }else{
            //设置级联信息
            DataPedigreeHelper.initCascadeField(menu, query.getParentId(), this::getOneByUid, this::getLastFormNextChildrenByUid);
        }
        //持久化
        this.save(menu);
        return menu;

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void removeByUid(String uid) {
        MenuPermission menu = this.getOneByUid(uid);
        AssertUtil.isNotNull(menu, ServiceRuntimeException.instance(ApiCodeUser.PARAMETER_ERROR));
        //自身及其子数据
        LambdaQueryWrapper<MenuPermission> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(MenuPermission::getFamilyId, menu.getFamilyId());
        queryWrapper.like(MenuPermission::getPedigree, menu.getPedigree());
        List<MenuPermission> list = this.list(queryWrapper);
        List<String> menuUids = EntityUtil.extractProperty(list, MenuPermission::getUid);
        //删除关联
        this.roleMenuPermissionRelationService.removeInMenuPermissionUids(menuUids);
        this.userPermissionRelationService.removeByPermissionIds(menuUids);
        this.dataRelationService.removeByRelationIds(menuUids);
        //删除自身及其子数据
        this.remove(queryWrapper);

    }

    @Override
    public void updateByUid(String uid, MenuPermissionQuery query) {
        MenuPermission old = this.getOneByUid(uid);
        AssertUtil.isNotNull(old, ServiceRuntimeException.instance(ApiCodeUser.PARAMETER_ERROR));
        //不可更新字段
        query.setDataGroup(null).setParentId(null);
        //更新
        MenuPermission menu = BeanUtil.copyProperties(query, MenuPermission.class);
        this.update(menu, new LambdaQueryWrapper<MenuPermission>().eq(MenuPermission::getUid, uid));

        //权限关联更新
        if(StrUtil.isNotBlank(query.getPermission()) && !query.getPermission().equals(old.getPermission())){
            this.userPermissionRelationService.updateByPermission(old.getPermission() ,query.getPermission());
        }

        //更新状态，子项同步更新
        if(query.getStatus() == null){
           return;
        }
        List<MenuPermission> children = this.getListChildren(old.getUid(),new MenuPermissionQuery());
        if(CollectionUtil.isEmpty(children)){
            return;
        }
        List<String> uidList = EntityUtil.extractProperty(children, MenuPermission::getUid);
        this.update(new MenuPermission().setStatus(query.getStatus()), new LambdaQueryWrapper<MenuPermission>().in(MenuPermission::getUid, uidList));
    }

    @Override
    public MenuPermission getOneByUid(String uid) {
        return this.getOne(new LambdaQueryWrapper<MenuPermission>().eq(MenuPermission::getUid, uid));
    }

    @Override
    public MenuPermission getLastFormNextChildrenByUid(String uid) {
        LambdaQueryWrapper<MenuPermission> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(MenuPermission::getParentId ,uid).orderByDesc(MenuPermission::getId).last("LIMIT 1");
        return getOne(queryWrapper);
    }

    @Override
    public PageInfo<MenuPermission> getPage(MenuPermissionQuery query) {
        //分页
        PageHelper.startPage(query.getPageNum(), query.getPageSize());
        return new PageInfo<>(this.getList(query));
    }

    @Override
    public List<MenuPermission> getList(MenuPermissionQuery query) {
        return this.list(this.createBaseWrapper(query));
    }

    @Override
    public List<MenuPermission> getListChildren(String parentId ,MenuPermissionQuery query) {
        query.setParentId(null);
        return this.list(checkAndGetQueryNextWrapper(parentId ,query));
    }

    @Override
    public PageInfo<MenuPermission> getPageChildren(String parentId ,MenuPermissionQuery query) {
        query.setParentId(null);
        LambdaQueryWrapper<MenuPermission> queryWrapper = checkAndGetQueryNextWrapper(parentId ,query);
        //分页
        PageHelper.startPage(query.getPageNum(), query.getPageSize());
        return new PageInfo<>(this.list(queryWrapper));
    }

    @Override
    public List<MenuPermission> getListNextChildren(String parentId ,MenuPermissionQuery query) {
        query.setParentId(parentId);
        LambdaQueryWrapper<MenuPermission> queryWrapper = this.createBaseWrapper(query);
        //没有上级菜单就查询顶层数据
        if (query == null || StrUtil.isBlank(query.getParentId())) {
            queryWrapper.and(andWrapper -> {
                andWrapper.isNull(MenuPermission::getParentId).or().eq(MenuPermission::getParentId, "");
            });
        }
        return this.list(queryWrapper);
    }

    @Override
    public PageInfo<MenuPermission> getPageNextChildren(String parentId ,MenuPermissionQuery query) {
        query.setParentId(parentId);
        //分页
        PageHelper.startPage(query.getPageNum(), query.getPageSize());
        return new PageInfo<>(this.getListNextChildren(parentId,query));
    }

    @Override
    public List<MenuPermission> getRelationListByUserUid(String userUid, MenuPermissionQuery query) {
        //只能查询启用状态的
        query.setStatus(StatusCommonEnum.enabled.getValue());

        List<UserRoleRelation> userRoleRelationList = this.userRoleRelationService.getListByUserUid(userUid);
        if(CollectionUtil.isEmpty(userRoleRelationList)){
            return Collections.emptyList();
        }
        List<String> roleUids = EntityUtil.extractProperty(userRoleRelationList ,UserRoleRelation::getRoleUid);
        return getListByRoleUid(roleUids);
    }

    @Override
    public List<MenuPermission> getVisibleByUserUid(String userUid, MenuPermissionQuery query) {
        query = query == null ? new MenuPermissionQuery() : query;
        DataRelationQuery dataRelationQuery = new DataRelationQuery().setHostId(userUid).setType(DataRelationEnum.userMenuPermissionShare.getValue());
        List<DataRelation> dataRelationList = this.dataRelationService.getList(dataRelationQuery);
        List<String> relationMenuPermissionUids = EntityUtil.extractProperty(dataRelationList ,DataRelation::getRelationId);


        query.setStatus(StatusCommonEnum.enabled.getValue());
        LambdaQueryWrapper<MenuPermission> queryWrapper = createBaseWrapper(query);
        queryWrapper.and(andWrapper->{
           andWrapper.in(CollectionUtil.isNotEmpty(relationMenuPermissionUids) ,MenuPermission::getUid ,relationMenuPermissionUids).or().eq(MenuPermission::getCreatorId ,ClientContextHelper.getClientInfo().getId().toString());
        });
        return list(queryWrapper);
    }

    @Override
    public List<MenuPermission> getListByRoleUid(List<String> roleUids) {
        if(CollectionUtil.isEmpty(roleUids)){
            return Collections.emptyList();
        }
        List<RoleMenuPermissionRelation> roleMenuPermissionRelationList = this.roleMenuPermissionRelationService.getListInRoleUid(roleUids);
        if (CollectionUtil.isEmpty(roleMenuPermissionRelationList)) {
            return Collections.emptyList();
        }
        List<String> menuUidList = EntityUtil.extractProperty(roleMenuPermissionRelationList, RoleMenuPermissionRelation::getMenuPermissionUid);
        return this.list(new LambdaQueryWrapper<MenuPermission>().in(MenuPermission::getUid, menuUidList));
    }

    @Override
    public void resetPedigree(List<MenuPermission> menuList) {
        this.updateBatchById(menuList);
    }

    @Override
    public List<MenuPermission> getListByUids(List<String> menuPermissionUids) {
        if(CollectionUtil.isEmpty(menuPermissionUids)){
            return Collections.emptyList();
        }
        return this.list(new LambdaQueryWrapper<MenuPermission>().in(MenuPermission::getUid, menuPermissionUids));
    }

    @Override
    public void resetUserRelationShare(String userUid, List<String> menuPermissionUids) {
        this.dataRelationService.reset(DataRelationEnum.userMenuPermissionShare.getValue() ,userUid ,menuPermissionUids);
    }

    @Override
    public List<String> getVisibleMenusByUserUid(String userUid, MenuPermissionQuery query) {
        return getVisibleByUserUid(userUid ,query).stream().collect(ArrayList<String>::new ,(l ,r)->l.add(r.getMenu()) ,(l,r)->{}).stream().filter(s -> StrUtil.isNotBlank(s)).collect(Collectors.toList());
    }

    @Async
    @Override
    public void resetMenuPedigree(){
        List<MenuPermission> list = this.getList(new MenuPermissionQuery());

        List<MenuTreeBo> top = new ArrayList<>();

        Map<String , MenuTreeBo> keyToMap = new HashMap<>(list.size());
        list.forEach(menu -> {
            keyToMap.put(menu.getUid() , BeanUtil.toBean(menu ,MenuTreeBo.class));
            if(StrUtil.isBlank(menu.getParentId())) {
                top.add(keyToMap.get(menu.getUid()));
            }
        });

        //设置孩子
        keyToMap.entrySet().forEach(entry->{
            if(StrUtil.isBlank(entry.getValue().getParentId())){
                return;
            }
            MenuTreeBo p = keyToMap.get(entry.getValue().getParentId());
            if(p == null){
                System.out.println("没有上级：" + entry.getValue());
            }else{
                p.getChildren().add(entry.getValue());
            }
        });
        System.out.println(JSONUtil.toJsonStr(top));
        List<MenuPermission> menuList = new ArrayList<>();
        resetPedigreeAndSetMenu(menuList ,top ,null ,1);
        System.out.println(JSONUtil.toJsonStr(top));

        this.resetPedigree(menuList);
    }

    private void resetPedigreeAndSetMenu(List<MenuPermission> menuList , List<MenuTreeBo> treeBoList , String parentPath , int level){
        if(CollectionUtil.isEmpty(treeBoList)){
            return;
        }
        for(int i = 0 ;i < treeBoList.size() ;++i){
            MenuTreeBo menuT = treeBoList.get(i);
            menuT.setPedigree(DataPathHelper.createPath(parentPath,i)).setGeneration(level);
            menuList.add(BeanUtil.toBean(menuT , MenuPermission.class));
            resetPedigreeAndSetMenu(menuList ,menuT.getChildren() ,menuT.getPedigree() ,level + 1);
        }
    }

    /**
     * 封装查询下级数据条件
     * @param query
     * @return
     */
    private LambdaQueryWrapper<MenuPermission> checkAndGetQueryNextWrapper(String parentId ,MenuPermissionQuery query){
        if (StrUtil.isBlank(parentId)) {
            ServiceRuntimeException.throw0(ApiCodeUser.PARAMETER_ERROR);
        }
        query = query == null ? new MenuPermissionQuery() : query;
        MenuPermission parent = this.getOneByUid(parentId);
        AssertUtil.isNotNull(parent, ServiceRuntimeException.instance(ApiCodeUser.PARAMETER_ERROR));
        LambdaQueryWrapper<MenuPermission> queryWrapper = this.createBaseWrapper(query);
        queryWrapper.eq(MenuPermission::getFamilyId, parent.getFamilyId());
        queryWrapper.like(MenuPermission::getPedigree, parent.getPedigree())
                .ne(MenuPermission::getPedigree, parent.getPedigree());
        return queryWrapper;
    }

    private LambdaQueryWrapper<MenuPermission> createBaseWrapper(MenuPermissionQuery query) {
        LambdaQueryWrapper<MenuPermission> queryWrapper = new LambdaQueryWrapper<>();
        //排序
        if (query != null && CollectionUtil.isNotEmpty(query.getSorts())) {
            //自定义排序
            MybatisPlusHelper.orderAndIgnoreError(MenuPermission.class, queryWrapper, query.getSorts());
        } else {
            //默认排序
            queryWrapper.orderByDesc(MenuPermission::getSort, MenuPermission::getCreatedTime);
            queryWrapper.orderByAsc(MenuPermission::getFamilyId, MenuPermission::getDataGroup, MenuPermission::getDataMark, MenuPermission::getGeneration);

        }
        if (query != null) {
            //右模糊
            MybatisPlusHelper.likeRightIncloude(MenuPermission.class, queryWrapper, query, MenuPermission::getMenu, MenuPermission::getName);
            //等值
            MybatisPlusHelper.eqIncloude(MenuPermission.class, queryWrapper, query
                    , MenuPermission::getStatus, MenuPermission::getDataGroup, MenuPermission::getDataMark, MenuPermission::getParentId);
        }

        return queryWrapper;
    }
}
