package com.njzscloud.supervisory.menu.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.IService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.njzscloud.common.core.ex.Exceptions;
import com.njzscloud.common.mp.support.PageResult;
import com.njzscloud.common.security.support.MenuResource;
import com.njzscloud.supervisory.menu.contant.MenuCategory;
import com.njzscloud.supervisory.menu.mapper.SysMenuMapper;
import com.njzscloud.supervisory.menu.pojo.*;
import com.njzscloud.supervisory.resource.pojo.SysResourceEntity;
import com.njzscloud.supervisory.resource.service.SysResourceService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>sys_menu</p>
 * <p>菜单信息表</p>
 */
@Slf4j
@Service
public class SysMenuService extends ServiceImpl<SysMenuMapper, SysMenuEntity> implements IService<SysMenuEntity> {

    @Autowired
    private SysResourceService sysResourceService;

    /**
     * 新增
     *
     * @param menuAddParam 数据
     * @return
     */

    @Transactional(rollbackFor = Exception.class)
    public Long add(MenuAddParam menuAddParam) {
        String sn = menuAddParam.getSn();
        boolean exists = this.exists(Wrappers.<SysMenuEntity>lambdaQuery().eq(SysMenuEntity::getSn, sn));
        Assert.isFalse(exists, () -> Exceptions.exception("资源编码重复"));
        SysMenuEntity sysMenuEntity = BeanUtil.copyProperties(menuAddParam, SysMenuEntity.class);
        Long pid = sysMenuEntity.getPid();
        if (pid == null) {
            sysMenuEntity.setPid(0L);
            pid = 0L;
        }
        String title = sysMenuEntity.getTitle();
        if (pid == 0) {
            sysMenuEntity.setTier(1);
            sysMenuEntity.setBreadcrumb(CollUtil.newArrayList(title));
        } else {
            SysMenuEntity parent = this.getById(pid);
            Assert.notNull(parent, () -> Exceptions.exception("上级菜单不存在"));
            sysMenuEntity.setTier(parent.getTier() + 1);
            List<String> breadcrumb = parent.getBreadcrumb();
            breadcrumb.add(title);
            sysMenuEntity.setBreadcrumb(breadcrumb);
        }
        this.save(sysMenuEntity);
        Long sysMenuEntityId = sysMenuEntity.getId();
        exists = sysResourceService.exists(Wrappers.<SysResourceEntity>lambdaQuery().eq(SysResourceEntity::getSn, sn));
        Assert.isFalse(exists, () -> Exceptions.exception("资源编码重复"));
        sysResourceService.save(new SysResourceEntity()
                .setSn(sn)
                .setDataId(sysMenuEntityId)
                .setTableName("sys_menu")
                .setMemo("菜单资源-" + menuAddParam.getMenuCategory().getTxt() + "-" + menuAddParam.getTitle())
        );
        return sysMenuEntityId;
    }

    /**
     * 修改
     *
     * @param menuModifyParam 数据
     */

    @Transactional(rollbackFor = Exception.class)
    public void modify(MenuModifyParam menuModifyParam) {
        SysMenuEntity sysMenuEntity = BeanUtil.copyProperties(menuModifyParam, SysMenuEntity.class);
        Long id = sysMenuEntity.getId();
        Long pid = sysMenuEntity.getPid();
        SysMenuEntity oldSysMenuEntity = this.getById(id);
        Assert.notNull(oldSysMenuEntity, () -> Exceptions.exception("菜单不存在"));
        MenuCategory menuCategory = oldSysMenuEntity.getMenuCategory();
        String routeName = sysMenuEntity.getRouteName();

        if (menuCategory == MenuCategory.Page || menuCategory == MenuCategory.SubPage && routeName != null) {
            Assert.notBlank(routeName, () -> Exceptions.exception("路由名称不能为空"));
        } else if (menuCategory == MenuCategory.Catalog || menuCategory == MenuCategory.Btn && routeName != null) {
            Assert.isTrue(StrUtil.isBlank(routeName), () -> Exceptions.exception("菜单目录和按钮不用指定路由名称"));
        }

        if (pid != null && !pid.equals(oldSysMenuEntity.getPid()) && menuCategory == MenuCategory.Catalog) {
            SysMenuEntity parent = this.getById(pid);
            String title = sysMenuEntity.getTitle();
            List<String> breadcrumb = parent.getBreadcrumb();
            breadcrumb.add(StrUtil.isBlank(title) ? oldSysMenuEntity.getTitle() : title);
            sysMenuEntity.setBreadcrumb(breadcrumb)
                    .setTier(parent.getTier() + 1);

            this.modifyChild(sysMenuEntity);
        }

        this.updateById(sysMenuEntity);

        String title = menuModifyParam.getTitle();
        if (StrUtil.isBlank(title)) return;
        sysResourceService.update(Wrappers.<SysResourceEntity>lambdaUpdate()
                .eq(SysResourceEntity::getTableName, "sys_menu")
                .eq(SysResourceEntity::getDataId, id)
                .set(SysResourceEntity::getMemo, "菜单资源-" + oldSysMenuEntity.getMenuCategory().getTxt() + "-" + title));
    }

    private void modifyChild(SysMenuEntity sysMenuEntity) {
        List<String> breadcrumb = sysMenuEntity.getBreadcrumb();
        int tier = sysMenuEntity.getTier() + 1;
        this.list(Wrappers.<SysMenuEntity>lambdaQuery().eq(SysMenuEntity::getPid, sysMenuEntity.getId()))
                .stream()
                .map(it -> {
                    List<String> temp = CollUtil.newArrayList(breadcrumb);
                    temp.add(it.getTitle());
                    return new SysMenuEntity()
                            .setId(it.getId())
                            .setBreadcrumb(temp)
                            .setTier(tier);
                })
                .forEach(this::modifyChild);
    }

    /**
     * 删除
     *
     * @param ids Id
     */

    @Transactional(rollbackFor = Exception.class)
    public void del(List<Long> ids) {
        this.removeBatchByIds(ids);
        sysResourceService.remove(Wrappers.<SysResourceEntity>lambdaQuery()
                .eq(SysResourceEntity::getTableName, "sys_menu")
                .in(SysResourceEntity::getDataId, ids)
        );
    }

    /**
     * 详情
     *
     * @param id Id
     * @return SysMenuListVO 结果
     */

    public MenuDetailResult detail(Long id) {
        return BeanUtil.copyProperties(this.getById(id), MenuDetailResult.class);
    }


    public List<MenuDetailResult> list(Long pid, MenuSearchParam menuSearchParam) {
        String title = menuSearchParam.getTitle();
        String routeName = menuSearchParam.getRouteName();
        return this.list(Wrappers.<SysMenuEntity>lambdaQuery()
                        .eq(pid != null, SysMenuEntity::getPid, pid)
                        .like(StrUtil.isNotBlank(title), SysMenuEntity::getTitle, title)
                        .like(StrUtil.isNotBlank(routeName), SysMenuEntity::getRouteName, routeName)
                        .orderByAsc(Arrays.asList(SysMenuEntity::getTier, SysMenuEntity::getSort)))
                .stream()
                .map(it -> BeanUtil.copyProperties(it, MenuDetailResult.class))
                .collect(Collectors.toList());
    }

    public List<MenuResource> listUserMenu(Long userId) {
        List<SysMenuEntity> sysMenuEntities = baseMapper.selectMenuByUserId(userId);
        return sysMenuEntities.stream()
                .map(it -> BeanUtil.copyProperties(it, MenuResource.class)
                        .setMenuCategory(it.getMenuCategory().getVal())
                )
                .collect(Collectors.toList());
    }


    public PageResult<MenuDetailResult> pageList(IPage<SysMenuEntity> page, MenuSearchParam menuSearchParam) {
        String title = menuSearchParam.getTitle();
        String routeName = menuSearchParam.getRouteName();
        page = this.page(page, Wrappers.<SysMenuEntity>lambdaQuery()
                .like(StrUtil.isNotBlank(title), SysMenuEntity::getTitle, title)
                .like(StrUtil.isNotBlank(routeName), SysMenuEntity::getRouteName, routeName));
        return PageResult.of(page.convert(it -> BeanUtil.copyProperties(it, MenuDetailResult.class)));
    }
}
