package com.mosty.common.config.controller;


import cn.hutool.core.bean.BeanUtil;
import cn.hutool.db.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.google.common.collect.Lists;
import com.mosty.common.base.constant.enums.DeletedEnum;
import com.mosty.common.base.constant.enums.DictTypeEnum;
import com.mosty.common.base.domain.ResponseResult;
import com.mosty.common.base.entity.log.BusinessType;
import com.mosty.common.base.entity.log.Log;
import com.mosty.common.base.exception.Asserts;
import com.mosty.common.base.util.IpUtil;
import com.mosty.common.config.Excel.DictUtils;
import com.mosty.common.config.config.DictElementConfig;
import com.mosty.common.config.constant.enums.DictElementEnum;
import com.mosty.common.config.entity.SysDict;
import com.mosty.common.config.entity.SysDictItem;
import com.mosty.common.config.entity.vo.*;
import com.mosty.common.config.service.SysDictItemService;
import com.mosty.common.config.service.SysDictService;
import com.mosty.common.token.JwtSysUser;
import com.mosty.common.token.UserInfo;
import com.mosty.common.token.UserInfoManager;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.util.*;
import java.util.stream.Collectors;

import static com.mosty.common.config.config.DictElementConfig.getDictCode;

/**
 * <p>
 * 字典类别配置表 前端控制器
 * </p>
 *
 * @author kevin
 * @since 2022-02-09
 */
@SuppressWarnings("unused")
@RestController
@AllArgsConstructor
@RequestMapping("/sysDict")
@Api(tags = "字典接口")
@Slf4j
public class SysDictController {

    private final SysDictService sysDictService;
    private final SysDictItemService sysDictItemService;
    private final DictElementConfig dictElementConfig;

    /**
     * 添加字典信息
     *
     * @param addSysDictVO 字典对象
     * @return 添加结果
     */
    @JwtSysUser
    @PostMapping("addSysDict")
    @Log(title = "字典功能", businessType = BusinessType.INSERT)
    @ApiOperation(value = "添加字典信息", httpMethod = "POST", response = Boolean.class)
    public ResponseResult<Boolean> addSysDict(@RequestBody @Valid AddSysDictVO addSysDictVO) {

        SysDict sysDict = new SysDict();

        sysDict.setZdmc(addSysDictVO.getZdmc());
        sysDict.setZdywlb(addSysDictVO.getZdywlb());
        sysDict.setZdbh(addSysDictVO.getZdbh());
        sysDict.setYybz(addSysDictVO.getYybz());
        sysDict.setBz(addSysDictVO.getBz());
        sysDict.setZdlx(addSysDictVO.getZdlx());

        UserInfo userInfo = UserInfoManager.get();
        Asserts.checkAuth(userInfo == null, "用户信息不存在");
        Asserts.checkAuth(userInfo.getDeptId() == null, "用户部门信息不存在");
        Asserts.checkAuth(userInfo.getUserId() == null, "用户id信息不存在");
        sysDict.setXtZxbz(DeletedEnum.NATURE.code);

        sysDict.setXtZhxgsj(new Date());
        sysDict.setXtZhxgrid(userInfo.getUserId().toString());
        sysDict.setXtZhxgrxm(userInfo.getUserName());
        sysDict.setXtZhxgrbmid(userInfo.getDeptId().toString());
        sysDict.setXtZhxgrbm(userInfo.getDeptName());
        sysDict.setXtCjsj(new Date());

        sysDict.setXtLrsj(new Date());
        sysDict.setXtLrrid(userInfo.getUserId().toString());
        sysDict.setXtLrrxm(userInfo.getUserName());
        sysDict.setXtLrrbmid(userInfo.getDeptId().toString());
        sysDict.setXtLrrbm(userInfo.getDeptName());
        SysDict one = sysDictService.getOne(new LambdaQueryWrapper<SysDict>()
                .eq(SysDict::getZdbh, sysDict.getZdbh()));
        Asserts.check(Objects.nonNull(one), "当前字典编码已经存在！");
        // 获取ip地址
        String ipAddress = IpUtil.getIpAddress();
        sysDict.setXtLrip(ipAddress);
        sysDict.setXtZhxgip(ipAddress);

        int insert = sysDictService.getBaseMapper().insert(sysDict);
        if (insert > 0) {
            DictUtils.setDictCache(sysDict.getZdbh(), null);
        }
        return ResponseResult.success(Boolean.TRUE);
    }

    /**
     * 修改字典信息
     *
     * @param editSysDictVo 字典对象
     * @return 添加结果
     */
    @JwtSysUser
    @PostMapping("updateSysDict")
    @Log(title = "字典功能", businessType = BusinessType.UPDATE)
    @ApiOperation(value = "修改字典信息", httpMethod = "POST", response = Boolean.class)
    public ResponseResult<Boolean> updateSysDict(@RequestBody @Valid EditSysDictVO editSysDictVo,
                                                 HttpServletRequest servletRequest) {
        Asserts.check(editSysDictVo.getId() == null, "主键id不能为空！");
        SysDict oldSysDict = sysDictService.getBaseMapper().selectById(editSysDictVo.getId());
        Asserts.check(oldSysDict == null, "主键为 %s 的字典信息不存在", editSysDictVo.getId());

        // 获取ip地址
        String ipAddress = IpUtil.getIpAddress(servletRequest);
        oldSysDict.setXtZhxgip(ipAddress);

        oldSysDict.setZdmc(editSysDictVo.getZdmc());
        oldSysDict.setZdywlb(editSysDictVo.getZdywlb());
        oldSysDict.setZdbh(editSysDictVo.getZdbh());
        oldSysDict.setYybz(editSysDictVo.getYybz());
        oldSysDict.setBz(editSysDictVo.getBz());
        oldSysDict.setZdlx(editSysDictVo.getZdlx());
        oldSysDict.setXtZxbz(editSysDictVo.getXtZxbz());
        UserInfo userInfo = UserInfoManager.get();
        Asserts.checkAuth(userInfo == null, "用户信息不存在");
        Asserts.checkAuth(userInfo.getDeptId() == null, "用户部门信息不存在");
        Asserts.checkAuth(userInfo.getUserId() == null, "用户id信息不存在");

        oldSysDict.setXtZhxgsj(new Date());
        oldSysDict.setXtZhxgrid(userInfo.getUserId().toString());
        oldSysDict.setXtZhxgrxm(userInfo.getUserName());
        oldSysDict.setXtZhxgrbmid(userInfo.getDeptId().toString());
        oldSysDict.setXtZhxgrbm(userInfo.getDeptName());

        int i = sysDictService.getBaseMapper().updateById(oldSysDict);
        if (i > 0) {
            List<SysDictItem> dictDatas = this.sysDictItemService.getBaseMapper().selectList(new LambdaQueryWrapper<SysDictItem>()
                    .eq(SysDictItem::getXtZxbz, 0)
                    .eq(SysDictItem::getZdbh, oldSysDict.getZdbh())
            );
            DictUtils.setDictCache(oldSysDict.getZdbh(), dictDatas);
        }


        return ResponseResult.success(Boolean.TRUE);
    }

    /**
     * 修改字典信息
     *
     * @param deleteVO 字典删除信息
     * @return 删除结果
     */
    @JwtSysUser
    @PostMapping("deleteSysDict")
    @Log(title = "字典功能", businessType = BusinessType.DELETE)
    @ApiOperation(value = "删除字典信息", httpMethod = "POST", response = Boolean.class)
    public ResponseResult<Boolean> deleteSysDict(@RequestBody DeleteVO deleteVO,
                                                 HttpServletRequest servletRequest) {
        SysDict oldSysDict = sysDictService.getBaseMapper().selectById(deleteVO.getId());
        Asserts.check(oldSysDict == null, "主键为 %s 的字典信息不存在", deleteVO.getId());

        QueryWrapper<SysDictItem> childQuery = new QueryWrapper<>();
        childQuery.and(wrapper -> wrapper.eq("zd_id", oldSysDict.getId()));
        childQuery.and(wrapper -> wrapper.eq("xt_zxbz", DeletedEnum.NATURE.code));
        List<SysDictItem> list = sysDictItemService.list(childQuery);
        Asserts.check(CollectionUtils.isNotEmpty(list), "当前节点下有子节点，请先删除子节点！");

        // 获取ip地址
        String ipAddress = IpUtil.getIpAddress(servletRequest);
        oldSysDict.setXtZhxgip(ipAddress);

        UserInfo userInfo = UserInfoManager.get();
        Asserts.checkAuth(userInfo == null, "用户信息不存在");
        Asserts.checkAuth(userInfo.getDeptId() == null, "用户部门信息不存在");
        Asserts.checkAuth(userInfo.getUserId() == null, "用户id信息不存在");

        oldSysDict.setXtZhxgsj(new Date());
        oldSysDict.setXtZhxgrid(userInfo.getUserId().toString());
        oldSysDict.setXtZhxgrxm(userInfo.getUserName());
        oldSysDict.setXtZhxgrbmid(userInfo.getDeptId().toString());
        oldSysDict.setXtZhxgrbm(userInfo.getDeptName());

        oldSysDict.setXtZxbz(DeletedEnum.DELETED.code);
        oldSysDict.setXtZxyy(deleteVO.getZxyy());

        sysDictService.getBaseMapper().updateById(oldSysDict);

        //删除缓存
        DictUtils.removeDictCache(oldSysDict.getZdbh());

        return ResponseResult.success(Boolean.TRUE);
    }

    /**
     * 根据字典编号查询字典信息
     *
     * @return 字典信息
     */
    @GetMapping("getSysDictByCode")
    @ApiOperation(value = "根据字典编号查询字典信息", httpMethod = "GET", response = SysDictVO.class)
    public ResponseResult<SysDictVO> getSysDictByCode(SysDictQueryVo vo) {
        Asserts.check(StringUtils.isBlank(vo.getDictCode()), "查询的字典编号不能为空！");
        return getSysDictVOResponseResult(vo);
    }



    /**
     * 根据字典组件枚举，查询字典信息
     *
     * @param dictElementEnum 字典组件枚举
     * @return 字典信息
     */
    @GetMapping("getElementSysDict")
    @ApiOperation(value = "根据字典组件枚举，查询字典信息", httpMethod = "GET", response = SysDictVO.class)
    public ResponseResult<SysDictVO> getElementSysDict(DictElementEnum dictElementEnum) {
        // 获取组件编码，可以中配置中修改
        String dictCode = getDictCode(dictElementEnum);
        SysDictQueryVo vo = new SysDictQueryVo();
        vo.setDictCode(dictCode);
        return getSysDictVOResponseResult(vo);
    }

    /**
     * 根据字典编码获取字典信息
     *
     * @return 字典信息
     */
    private ResponseResult<SysDictVO> getSysDictVOResponseResult(SysDictQueryVo vo) {

        QueryWrapper<SysDict> dictWrapper = new QueryWrapper<>();
        dictWrapper.and(wrapper -> wrapper.eq("zdbh", vo.getDictCode()));
        SysDict sysDict = sysDictService.getOne(dictWrapper);
        Asserts.check(sysDict == null, "字典编号 %s 对应的字典不存在", vo.getDictCode());
        SysDictVO sysDictVO = new SysDictVO();
        BeanUtil.copyProperties(sysDict, sysDictVO, true);

        //先查redis
        List<SysDictItem> list = DictUtils.getDictCache(vo.getDictCode());
        if (!CollectionUtils.isEmpty(list)) {
            if (StringUtils.isNotBlank(vo.getZdmc())) {
                list = list.stream().filter(v -> v.getZdmc().contains(vo.getZdmc())).collect(Collectors.toList());
            }
        } else {
            QueryWrapper<SysDictItem> dictItemWrapper = new QueryWrapper<>();
            dictItemWrapper.and(wrapper -> wrapper.eq("zdbh", vo.getDictCode()));
            dictItemWrapper.and(wrapper -> wrapper.eq("xt_zxbz", DeletedEnum.NATURE.code)
                    .like(StringUtils.isNotBlank(vo.getZdmc()), "zdmc", vo.getZdmc()))
                    .orderByAsc("dm");
            list = sysDictItemService.list(dictItemWrapper);
        }

        if (DictTypeEnum.NATURE.code.equals(sysDict.getZdlx())) {
            int expectedSize = CollectionUtils.isEmpty(list) ? 2 : list.size();
            List<SysDictItemVO> itemList = Lists.newArrayListWithExpectedSize(expectedSize);
            if (CollectionUtils.isNotEmpty(list)) {
                itemList = BeanUtil.copyToList(list, SysDictItemVO.class);
            }
            sysDictVO.setItemList(itemList);
        } else {
            if (CollectionUtils.isNotEmpty(list)) {
                List<SysDictItemVO> natureList = list.stream().filter(dept -> DeletedEnum.NATURE.code.equals(dept.getXtZxbz()))
                        .map(dept -> BeanUtil.copyProperties(dept, SysDictItemVO.class)).collect(Collectors.toList());
                if (CollectionUtils.isNotEmpty(natureList)) {
                    // 递归树
                    wrapChildList(sysDictVO, null, natureList);
                }
            }
        }
        return ResponseResult.success(sysDictVO);
    }

    @GetMapping("selectPage")
    @ApiOperation(value = "分页查询字典信息", httpMethod = "GET", response = SysDict.class)
    public ResponseResult<IPage<SysDict>> selectPage(DictPage dictPage) {
        IPage<SysDict> userIPage = sysDictService.selectByPage(dictPage);
        return ResponseResult.success(userIPage);
    }

    /**
     * 递归组装字典信息
     *
     * @param sysDictVO     字典信息
     * @param sysDictItemVO 字典明细信息
     * @param natureList    所有字典信息
     */
    public void wrapChildList(SysDictVO sysDictVO, SysDictItemVO sysDictItemVO, List<SysDictItemVO> natureList) {
        Long rootId = sysDictVO != null ? sysDictVO.getId() : sysDictItemVO.getId();
        List<SysDictItemVO> collect = natureList.stream().filter(dept -> rootId.equals(dept.getZdId()))
                .sorted(Comparator.comparing(SysDictItemVO::getPx).reversed()).collect(Collectors.toList());
        if (sysDictVO != null) {
            sysDictVO.setItemList(collect);
        } else {
            sysDictItemVO.setItemList(collect);
        }
        if (CollectionUtils.isNotEmpty(collect)) {
            collect.forEach(dictItem -> wrapChildList(null, dictItem, natureList));
        }
    }

}

