package com.gci.boot.modules.system.controller;


import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.gci.boot.common.log.annotation.AddSysLog;
import com.gci.boot.common.util.ParamsCheckUtil;
import com.gci.boot.common.util.QueryWrapperUtil;
import com.gci.boot.common.util.SqlInjectionCheckUtil;
import com.gci.boot.common.vo.Result;
import com.gci.boot.constant.CacheConstant;
import com.gci.boot.constant.CommonConstant;
import com.gci.boot.modules.system.entity.SysDict;
import com.gci.boot.modules.system.entity.SysDictItem;
import com.gci.boot.modules.system.service.ISysDictItemService;
import com.gci.boot.modules.system.service.ISysDictService;
import com.gci.boot.modules.system.vo.DictModel;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.web.bind.annotation.*;

import java.util.*;

/**
 * <p>
 * 前端控制器
 * </p>
 *
 * @author chenzhiwei
 * @since 2023-08-25
 */
@RestController
@RequestMapping("/sys/dict")
@Slf4j
public class SysDictController {
    @Autowired
    private ISysDictService sysDictService;
    @Autowired
    private ISysDictItemService sysDictItemService;

    @AddSysLog("查询字典列表")
    @GetMapping("/list")
    public Result<IPage<SysDict>> queryPageList(SysDict sysDict, String column, String order, @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
                                                @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize) {
        if(StringUtils.isBlank(column)){
            column = "create_time";
            order = "desc";
        }
        QueryWrapper<SysDict> queryWrapper = QueryWrapperUtil.builder()
                .table(SysDict.class)
                .like(SysDict::getDictName)
                .like(SysDict::getDictCode)
                .like(SysDict::getDescription)
                .orderColums(column)
                .orders(order)
                .buildFromObject(sysDict);
        Page<SysDict> page = new Page<SysDict>(pageNo, pageSize);
        IPage<SysDict> pageList = sysDictService.page(page, queryWrapper);
        log.debug("查询当前页：" + pageList.getCurrent());
        log.debug("查询当前页数量：" + pageList.getSize());
        log.debug("查询结果数量：" + pageList.getRecords().size());
        log.debug("数据总数：" + pageList.getTotal());
        return Result.ok(pageList);
    }


    /**
     * @param sysDict
     * @return
     * @功能：新增
     */
    @AddSysLog("添加字典")
    @PostMapping("/add")
    public Result<SysDict> add(@RequestBody SysDict sysDict) {
        ParamsCheckUtil.paramsAssert()
                .notBlank(sysDict.getDictCode(), "【字典编码】不能为空!")
                .notBlank(sysDict.getDictName(), "【字典名称】不能为空！")
                .notNull(sysDict.getType(), "【数据类型】不能为空！")
                .isTrue(sysDictService.lambdaQuery().eq(SysDict::getDictCode, sysDict.getDictCode()).count() == 0, "【字典编码】已存在!")
                .isTrue(sysDictService.lambdaQuery().eq(SysDict::getDictName, sysDict.getDictName()).count() == 0, "【字典名称】已存在!")
        ;
        sysDictService.save(sysDict);
        return Result.ok("保存成功！");
    }

    /**
     * @param sysDict
     * @return
     * @功能：编辑
     */
    @AddSysLog("编辑字典")
    @PutMapping("/edit")
    @CacheEvict(value = CacheConstant.SYS_DICT_CACHE, key = "#sysDict.id")
    public Result<SysDict> edit(@RequestBody SysDict sysDict) {
        ParamsCheckUtil.ParamsAssert paramsAssert = ParamsCheckUtil.paramsAssert()
                .notBlank(sysDict.getId(), "【字典ID】不能为空！");
        SysDict dict = sysDictService.getById(sysDict.getId());
        if (dict == null) {
            return Result.error("未找到对应实体");
        }
        paramsAssert.notBlank(sysDict.getDictCode(), "【字典编码】不能为空!")
                .notBlank(sysDict.getDictName(), "【字典名称】不能为空！")
                .notNull(sysDict.getType(), "【数据类型】不能为空！")
                .isTrue(sysDictService.lambdaQuery().ne(SysDict::getId, sysDict.getId()).eq(SysDict::getDictCode, sysDict.getDictCode()).count() == 0, "【字典编码】已存在!")
                .isTrue(sysDictService.lambdaQuery().ne(SysDict::getId, sysDict.getId()).eq(SysDict::getDictName, sysDict.getDictName()).count() == 0, "【字典名称】已存在!")
        ;
        sysDictService.updateById(sysDict);
        return Result.ok("编辑成功");
    }

    /**
     * @param id
     * @return
     * @功能：删除
     */
    @AddSysLog("删除字典")
    @DeleteMapping("/delete")
    @CacheEvict(value = CacheConstant.SYS_DICT_CACHE, key = "#id")
    public Result<SysDict> delete(String id) {
        sysDictService.removeById(id);
        return Result.ok("删除成功!");
    }

    /**
     * @param ids
     * @return
     * @功能：批量删除
     */
    @AddSysLog("批量删除字典")
    @DeleteMapping("/deleteBatch")
    @CacheEvict(value = CacheConstant.SYS_DICT_CACHE, allEntries = true)
    public Result<SysDict> deleteBatch(String ids) {
        if (StringUtils.isBlank(ids)) {
            return Result.error("参数不识别！");
        }
        sysDictService.removeByIds(Arrays.asList(ids.split(",")));
        return Result.ok("删除成功!");
    }


    /**
     * 前端加载所有数据字典
     *
     * @return
     */
    @GetMapping("/queryAllDictItems")
    public Result<?> loadAllDict() {
        Map<String, String> dictCodeMap = new HashMap<>();
        Map<String, List<DictModel>> res = new LinkedHashMap<>();
        sysDictService.lambdaQuery().list().forEach(dict -> {
            dictCodeMap.put(dict.getId(), dict.getDictCode());
            res.put(dict.getDictCode(), new ArrayList<>());
        });
        sysDictItemService.lambdaQuery()
                .eq(SysDictItem::getStatus, 1)
                .orderByAsc(SysDictItem::getSortOrder)
                .list()
                .forEach(item -> {
                    DictModel dictModel = new DictModel();
                    dictModel.setText(item.getItemText());
                    dictModel.setValue(item.getItemValue());
                    List<DictModel> dictModels = res.get(dictCodeMap.get(item.getDictId()));
                    if (dictModels != null) {
                        dictModels.add(dictModel);
                    }
                });

        log.debug("-------登录加载系统字典-----");
        log.debug("{}", res);
        return Result.ok(res);
    }

    /**
     * 获取字典数据
     *
     * @param dictCode 字典code
     * @param dictCode 表名,文本字段,code字段  | 举例：sys_user,realname,id
     * @return
     */
    @GetMapping("/getDictItems/{dictCode}")
    public Result<?> getDictItems(@PathVariable String dictCode) {
        log.info(" dictCode : " + dictCode);
        List<DictModel> ls;
        try {
            if (dictCode.indexOf(",") != -1) {
                //关联表字典（举例：sys_user,realname,id）
                String[] params = dictCode.split(",");

                if (params.length < 3) {
                    return Result.error("字典Code格式不正确！");
                }
                //SQL注入校验（只限制非法串改数据库）
                if (SqlInjectionCheckUtil.containsSqlInjection(params[0], params[1], params[2])) {
                    return Result.error("查询失败！参数存在SQL注入风险");
                }
                if (params.length == 4) {
                    //条件允许单引号‘
                    if (SqlInjectionCheckUtil.containsSqlInjection(params[3].replace("'", ""))) {
                        return Result.error("查询失败！参数存在SQL注入风险");
                    }
                    ls = sysDictService.queryTableDictItemsByCodeAndFilter(params[0], params[1], params[2], params[3]);
                } else if (params.length == 3) {
                    ls = sysDictService.queryTableDictItemsByCode(params[0], params[1], params[2]);
                } else {
                    return Result.error("字典Code格式不正确！");
                }
            } else {
                //字典表
                ls = sysDictService.queryDictItemsByCode(dictCode);
            }
        } catch (Exception e) {
            log.error("", e);
            return Result.error("字典Code格式不正确！");
        }

        return Result.ok(ls);
    }
}
