package com.zbkj.service.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.zbkj.common.constants.RedisConstants;
import com.zbkj.common.exception.CrmebException;
import com.zbkj.common.model.bcx.BcxProductMenu;
import com.zbkj.common.model.product.ProductCategory;
import com.zbkj.common.page.CommonPage;
import com.zbkj.common.request.BcxProductMenuRequest;
import com.zbkj.common.request.PageParamRequest;
import com.zbkj.common.response.BcxProductMenuResponse;
import com.zbkj.common.utils.RedisUtil;
import com.zbkj.common.utils.SecurityUtil;
import com.zbkj.common.vo.BcxProductMenuTree;
import com.zbkj.common.vo.LoginUserVo;
import com.zbkj.service.dao.BcxProductMenuDao;
import com.zbkj.service.service.BcxProductMenuService;
import com.zbkj.service.service.ProductCategoryService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 商城商品菜单 服务实现类
 */
@Service
public class BcxProductMenuServiceImpl extends ServiceImpl<BcxProductMenuDao, BcxProductMenu> implements BcxProductMenuService {

    @Resource
    private BcxProductMenuDao dao;

    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private ProductCategoryService productCategoryService;

    @Override
    public BcxProductMenu queryById(Integer id) {
        return dao.selectById(id);
    }

    @Override
    public PageInfo<BcxProductMenu> queryPagedList(BcxProductMenu request,
                                                   PageParamRequest pageParamRequest) {
        LambdaQueryWrapper<BcxProductMenu> lqw = new LambdaQueryWrapper<>();
        lqw.eq(BcxProductMenu::getId, request.getId());
        Page<BcxProductMenu> page = PageHelper.startPage(pageParamRequest.getPage(), pageParamRequest.getLimit());
        List<BcxProductMenu> sources = dao.selectList(lqw);
        if (CollUtil.isEmpty(sources)) {
            return CommonPage.copyPageInfo(page, CollUtil.newArrayList());
        }
        List<BcxProductMenu> result = transform2target(sources);
        return CommonPage.copyPageInfo(page, result);
    }

    private List<BcxProductMenu> transform2target(List<BcxProductMenu> sources) {
        List<BcxProductMenu> result = new ArrayList<>();
        for (BcxProductMenu source : sources) {
            BcxProductMenu target = new BcxProductMenu();
            BeanUtils.copyProperties(source, target);
            result.add(target);
        }
        return result;
    }

    @Override
    public Boolean create(BcxProductMenuRequest bcxProductMenuRequest) {
        LoginUserVo loginUserVo = SecurityUtil.getLoginUserVo();
        if (checkExist(bcxProductMenuRequest.getName(), bcxProductMenuRequest.getPid())) {
            throw new CrmebException("菜单已存在");
        }
        verifyProductMenuWhenUpsert(bcxProductMenuRequest);
        BcxProductMenu bcxProductMenu = new BcxProductMenu();
        BeanUtils.copyProperties(bcxProductMenuRequest, bcxProductMenu);
        bcxProductMenu.setId(null);
        bcxProductMenu.setCreatedBy(loginUserVo.getUser().getId());
        bcxProductMenu.setUpdatedBy(loginUserVo.getUser().getId());
        boolean success = save(bcxProductMenu);
        if (success) {
            redisUtil.delete(RedisConstants.PRODUCT_MENU_CACHE_LIST_KEY);
        }
        return success;
    }

    private boolean checkExist(String name, Integer pid) {
        LambdaQueryWrapper<BcxProductMenu> lqw = new LambdaQueryWrapper<>();
        lqw.eq(BcxProductMenu::getPid, pid);
        lqw.eq(BcxProductMenu::getName, name);
        BcxProductMenu bcxProductMenu = dao.selectOne(lqw);
        return ObjectUtil.isNotNull(bcxProductMenu) ? Boolean.TRUE : Boolean.FALSE;
    }

    public Boolean update(BcxProductMenuRequest bcxProductMenuRequest) {
        LoginUserVo loginUserVo = SecurityUtil.getLoginUserVo();
        verifyProductMenuWhenUpsert(bcxProductMenuRequest);
        BcxProductMenu bcxProductMenu = new BcxProductMenu();
        BeanUtils.copyProperties(bcxProductMenuRequest, bcxProductMenu);
        bcxProductMenu.setUpdatedBy(loginUserVo.getUser().getId());
        boolean success = updateById(bcxProductMenu);
        if (success) {
            redisUtil.delete(RedisConstants.PRODUCT_MENU_CACHE_LIST_KEY);
        }
        return success;
    }

    private void verifyProductMenuWhenUpsert(BcxProductMenuRequest bcxProductMenu) {
        if (!bcxProductMenu.getLevel().equals(1)) {
            if (bcxProductMenu.getPid().equals(0)) {
                throw new CrmebException("子级菜单，父级ID不能为0");
            }
        }
        Integer categoryId = bcxProductMenu.getCategoryId();
        ProductCategory category = productCategoryService.getById(categoryId);
        if (category != null && category.getLevel() != 1) {
            throw new CrmebException("只能关联到一级商品分类");
        }
    }

    public Boolean delete(Integer id) {
        BcxProductMenu menu = getById(id);
        if (menu == null) {
            throw new CrmebException("没有找到该菜单");
        }
        if (menu.getLevel() < 3) {
            List<BcxProductMenu> menuList = findAllChildListByPid(menu.getId(), menu.getLevel());
            if (CollUtil.isNotEmpty(menuList)) {
                throw new CrmebException("请先删除子级分类");
            }
        }
        boolean success = removeById(id);
        if (success) {
            redisUtil.delete(RedisConstants.PRODUCT_MENU_CACHE_LIST_KEY);
        }
        return success;
    }

    @Override
    public List<BcxProductMenu> findAllChildListByPid(Integer pid, Integer level) {
        LambdaQueryWrapper<BcxProductMenu> lqw = Wrappers.lambdaQuery();
        lqw.eq(BcxProductMenu::getPid, pid);
        if (level.equals(2)) {
            return dao.selectList(lqw);
        }
        // level == 1
        List<BcxProductMenu> menuList = dao.selectList(lqw);
        if (CollUtil.isEmpty(menuList)) {
            return menuList;
        }
        List<Integer> pidList = menuList.stream().map(BcxProductMenu::getId).collect(Collectors.toList());
        lqw.clear();
        lqw.in(BcxProductMenu::getPid, pidList);
        List<BcxProductMenu> thirdLevelList = dao.selectList(lqw);
        menuList.addAll(thirdLevelList);
        return menuList;
    }

    @Override
    public List<BcxProductMenuResponse> getCacheTree(Integer type) {
        if (redisUtil.exists(RedisConstants.PRODUCT_MENU_CACHE_LIST_KEY)) {
            List<BcxProductMenuResponse> tree = redisUtil.get(RedisConstants.PRODUCT_MENU_CACHE_LIST_KEY);
            return tree.stream().filter(m -> m.getType().equals(type)).collect(Collectors.toList());
        } else {
            LambdaQueryWrapper<BcxProductMenu> lqw = Wrappers.lambdaQuery();
            List<BcxProductMenu> menu = dao.selectList(lqw);
            if (CollUtil.isEmpty(menu)) {
                return CollUtil.newArrayList();
            }
            List<Integer> cateList = menu.stream().map(BcxProductMenu::getCategoryId).collect(Collectors.toList());
            Map<Integer, ProductCategory> cateMap = productCategoryService.getMapByIdList(cateList);
            List<BcxProductMenuResponse> voList = menu.stream().map(e -> {
                BcxProductMenuResponse cacheVo = new BcxProductMenuResponse();
                BeanUtils.copyProperties(e, cacheVo);
                if (cacheVo.getCategoryId() != null && cacheVo.getCategoryId() > 0 && cateMap.get(cacheVo.getCategoryId()) != null) {
                    cacheVo.setCategoryName(cateMap.get(cacheVo.getCategoryId()).getName());
                }
                return cacheVo;
            }).collect(Collectors.toList());
            BcxProductMenuTree menuTree = new BcxProductMenuTree(voList);
            List<BcxProductMenuResponse> tree = menuTree.buildTree();
            redisUtil.set(RedisConstants.PRODUCT_MENU_CACHE_LIST_KEY, tree);
            return tree.stream().filter(m -> m.getType().equals(type)).collect(Collectors.toList());
        }
    }
}
