package ${package.ServiceImpl};

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.orion.lang.define.wrapper.DataGrid;
import com.orion.lang.utils.Strings;
import com.orion.lang.utils.collect.Lists;
#if($meta.enableExport)
import com.orion.office.excel.writer.exporting.ExcelExport;
#end
import com.orion.visor.framework.common.constant.ErrorMessage;
#if($meta.enableExport)
import com.orion.visor.framework.common.utils.FileNames;
#end
import com.orion.visor.framework.common.utils.Valid;
#if($meta.enableCache)
import com.orion.visor.framework.redis.core.utils.RedisMaps;
import com.orion.visor.framework.redis.core.utils.barrier.CacheBarriers;
#end
#foreach($pkg in ${customModuleFilePackages})
import ${pkg}.*;
#end
import ${package.Entity}.${entity};
import ${package.Mapper}.${table.mapperName};
import ${package.Service}.${table.serviceName};
#if($meta.enableExport)
import com.orion.web.servlet.web.Servlets;
#end
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
#if($meta.enableExport)
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
#end
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

/**
 * $!{table.comment} 服务实现类
 *
 * @author ${author}
 * @version ${version}
 * @since ${date}
 */
@Slf4j
@Service
public class ${table.serviceImplName} implements ${table.serviceName} {

    @Resource
    private ${type}DAO ${typeLower}DAO;

    @Override
    public Long create${type}(${type}CreateRequest request) {
        log.info("${type}Service-create${type} request: {}", JSON.toJSONString(request));
        // 转换
        ${type}DO record = ${type}Convert.MAPPER.to(request);
        // 查询数据是否冲突
        this.check${type}Present(record);
        // 插入
        int effect = ${typeLower}DAO.insert(record);
        Long id = record.getId();
        log.info("${type}Service-create${type} id: {}, effect: {}", id, effect);
        #if($meta.enableCache)
        // 删除缓存
        RedisMaps.delete(${type}CacheKeyDefine.${typeConst});
        #end
        return id;
    }

    @Override
    public Integer update${type}ById(${type}UpdateRequest request) {
        Long id = Valid.notNull(request.getId(), ErrorMessage.ID_MISSING);
        log.info("${type}Service-update${type}ById id: {}, request: {}", id, JSON.toJSONString(request));
        // 查询
        ${type}DO record = ${typeLower}DAO.selectById(id);
        Valid.notNull(record, ErrorMessage.DATA_ABSENT);
        // 转换
        ${type}DO updateRecord = ${type}Convert.MAPPER.to(request);
        // 查询数据是否冲突
        this.check${type}Present(updateRecord);
        // 更新
        int effect = ${typeLower}DAO.updateById(updateRecord);
        log.info("${type}Service-update${type}ById effect: {}", effect);
        #if($meta.enableCache)
        // 删除缓存
        RedisMaps.delete(${type}CacheKeyDefine.${typeConst});
        #end
        return effect;
    }

    @Override
    public Integer update${type}(${type}QueryRequest query, ${type}UpdateRequest update) {
        log.info("${type}Service.update${type} query: {}, update: {}", JSON.toJSONString(query), JSON.toJSONString(update));
        // 条件
        LambdaQueryWrapper<${type}DO> wrapper = this.buildQueryWrapper(query);
        // 转换
        ${type}DO updateRecord = ${type}Convert.MAPPER.to(update);
        // 更新
        int effect = ${typeLower}DAO.update(updateRecord, wrapper);
        log.info("${type}Service.update${type} effect: {}", effect);
        #if($meta.enableCache)
        // 删除缓存
        RedisMaps.delete(${type}CacheKeyDefine.${typeConst});
        #end
        return effect;
    }

    @Override
    public ${type}VO get${type}ById(Long id) {
        // 查询
        ${type}DO record = ${typeLower}DAO.selectById(id);
        Valid.notNull(record, ErrorMessage.DATA_ABSENT);
        // 转换
        return ${type}Convert.MAPPER.to(record);
    }

    @Override
    public List<${type}VO> get${type}ByIdList(List<Long> idList) {
        // 查询
        List<${type}DO> records = ${typeLower}DAO.selectBatchIds(idList);
        if (records.isEmpty()) {
            return Lists.empty();
        }
        // 转换
        return ${type}Convert.MAPPER.to(records);
    }

    @Override
    public List<${type}VO> get${type}List(${type}QueryRequest request) {
        // 条件
        LambdaQueryWrapper<${type}DO> wrapper = this.buildQueryWrapper(request);
        // 查询
        return ${typeLower}DAO.of(wrapper).list(${type}Convert.MAPPER::to);
    }

    #if($meta.enableCache)
    @Override
    public List<${type}VO> get${type}ListByCache() {
        // 查询缓存
        List<${type}CacheDTO> list = RedisMaps.valuesJson(${type}CacheKeyDefine.${typeConst});
        if (list.isEmpty()) {
            // 查询数据库
            list = ${typeLower}DAO.of().list(${type}Convert.MAPPER::toCache);
            // 设置屏障 防止穿透
            CacheBarriers.checkBarrier(list, ${type}CacheDTO::new);
            // 设置缓存
            RedisMaps.putAllJson(${type}CacheKeyDefine.${typeConst}, s -> s.getId().toString(), list);
        }
        // 删除屏障
        CacheBarriers.removeBarrier(list);
        // 转换
        return list.stream()
                .map(${type}Convert.MAPPER::to)
                .sorted(Comparator.comparing(${type}VO::getId).reversed())
                .collect(Collectors.toList());
    }

    #end
    @Override
    public Long get${type}Count(${type}QueryRequest request) {
        // 条件
        LambdaQueryWrapper<${type}DO> wrapper = this.buildQueryWrapper(request);
        // 查询
        return ${typeLower}DAO.selectCount(wrapper);
    }

    @Override
    public DataGrid<${type}VO> get${type}Page(${type}QueryRequest request) {
        // 条件
        LambdaQueryWrapper<${type}DO> wrapper = this.buildQueryWrapper(request);
        // 查询
        return ${typeLower}DAO.of(wrapper)
                .page(request)
                .dataGrid(${type}Convert.MAPPER::to);
    }

    @Override
    public Integer delete${type}ById(Long id) {
        log.info("${type}Service-delete${type}ById id: {}", id);
        // 检查数据是否存在
        ${type}DO record = ${typeLower}DAO.selectById(id);
        Valid.notNull(record, ErrorMessage.DATA_ABSENT);
        // 删除
        int effect = ${typeLower}DAO.deleteById(id);
        log.info("${type}Service-delete${type}ById id: {}, effect: {}", id, effect);
        #if($meta.enableCache)
        // 删除缓存
        RedisMaps.delete(${type}CacheKeyDefine.${typeConst}, id);
        #end
        return effect;
    }

    @Override
    public Integer delete${type}ByIdList(List<Long> idList) {
        log.info("${type}Service-delete${type}ByIdList idList: {}", idList);
        int effect = ${typeLower}DAO.deleteBatchIds(idList);
        log.info("${type}Service-delete${type}ByIdList effect: {}", effect);
        #if($meta.enableCache)
        // 删除缓存
        RedisMaps.delete(${type}CacheKeyDefine.${typeConst}, idList);
        #end
        return effect;
    }

    @Override
    public Integer delete${type}(${type}QueryRequest request) {
        log.info("${type}Service.delete${type} request: {}", JSON.toJSONString(request));
        // 条件
        LambdaQueryWrapper<${type}DO> wrapper = this.buildQueryWrapper(request);
        // 删除
        int effect = ${typeLower}DAO.delete(wrapper);
        log.info("${type}Service.delete${type} effect: {}", effect);
        #if($meta.enableCache)
        // 删除缓存
        RedisMaps.delete(${type}CacheKeyDefine.${typeConst});
        #end
        return effect;
    }
    #if($meta.enableExport)

    @Override
    public void export${type}(${type}QueryRequest request, HttpServletResponse response) throws IOException {
        log.info("${type}Service.export${type} request: {}", JSON.toJSONString(request));
        // 条件
        LambdaQueryWrapper<${type}DO> wrapper = this.buildQueryWrapper(request);
        // 查询
        List<${type}Export> rows = ${typeLower}DAO.of(wrapper).list(${type}Convert.MAPPER::toExport);
        log.info("${type}Service.export${type} size: {}", rows.size());
        // 导出
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        ExcelExport.create(${type}Export.class)
                .addRows(rows)
                .write(out)
                .close();
        // 传输
        Servlets.transfer(response, out.toByteArray(), FileNames.exportName(${type}Export.TITLE));
    }
    #end

    /**
     * 检查对象是否存在
     *
     * @param domain domain
     */
    private void check${type}Present(${type}DO domain) {
        // 构造条件
        LambdaQueryWrapper<${type}DO> wrapper = ${typeLower}DAO.wrapper()
                // 更新时忽略当前记录
                .ne(${type}DO::getId, domain.getId())
                // 用其他字段做重复校验
                #foreach($field in ${table.fields})
                #if("$!field.propertyName" != "id")
                .eq(${type}DO::get${field.capitalName}, domain.get${field.capitalName}())#if(!$foreach.hasNext);#end
                #end
                #end
        // 检查是否存在
        boolean present = ${typeLower}DAO.of(wrapper).present();
        Valid.isFalse(present, ErrorMessage.DATA_PRESENT);
    }

    /**
     * 构建查询 wrapper
     *
     * @param request request
     * @return wrapper
     */
    private LambdaQueryWrapper<${type}DO> buildQueryWrapper(${type}QueryRequest request) {
        String searchValue = request.getSearchValue();
        return ${typeLower}DAO.wrapper()
                #foreach($field in ${table.fields})
                .eq(${type}DO::get${field.capitalName}, request.get${field.capitalName}())
                #end
                .and(Strings.isNotEmpty(searchValue), c -> c
                        #foreach($field in ${table.fields})
                        .eq(${type}DO::get${field.capitalName}, searchValue)#if($foreach.hasNext).or()#end
                        #end
                )
                .orderByDesc(${type}DO::getId);
    }

}
