package ${basePackage}.module.${table.moduleName}.service.${table.businessName};

import cn.hutool.core.collection.CollUtil;
import org.springframework.stereotype.Service;
import ${jakartaPackage}.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import ${basePackage}.module.${table.moduleName}.controller.${sceneEnum.basePackage}.${table.businessName}.vo.*;
import ${basePackage}.module.${table.moduleName}.dal.dataobject.${table.businessName}.${table.className}DO;
## 特殊：主子表专属逻辑
#foreach ($subTable in $subTables)
import ${basePackage}.module.${subTable.moduleName}.dal.dataobject.${subTable.businessName}.${subTable.className}DO;
#end
import ${PageResultClassName};
import ${PageParamClassName};
import ${BeanUtils};

import ${basePackage}.module.${table.moduleName}.dal.mysql.${table.businessName}.${table.className}Mapper;
## 特殊：主子表专属逻辑
#foreach ($subTable in $subTables)
#set ($index = $foreach.count - 1)
import ${basePackage}.module.${subTable.moduleName}.dal.mysql.${subTable.businessName}.${subTable.className}Mapper;
#end

import static ${ServiceExceptionUtilClassName}.exception;
import static ${CollectionUtilsClassName}.convertList;
import static ${CollectionUtilsClassName}.diffList;
import static ${basePackage}.module.${table.moduleName}.enums.ErrorCodeConstants.*;

/**
 * ${table.classComment} Service 实现类
 *
 * @author hake
 */
@Service
@Validated
public class ${table.className}ServiceImpl implements ${table.className}Service {

    @Resource
    private ${table.className}Mapper ${classNameVar}Mapper;
## 特殊：主子表专属逻辑
#foreach ($subTable in $subTables)
#set ($index = $foreach.count - 1)
    @Resource
    private ${subTable.className}Mapper ${subClassNameVars.get($index)}Mapper;
#end

    @Override
## 特殊：主子表专属逻辑（非 ERP 模式）
#if ( $subTables && $subTables.size() > 0 && $table.templateType != 11 )
    @Transactional(rollbackFor = Exception.class)
#end
    public ${primaryColumn.javaType} create${simpleClassName}(${saveReqVOClass} ${saveReqVOVar}) {
## 特殊：树表专属逻辑
#if ( $table.templateType == 2 )
#set ($TreeParentJavaField = $treeParentColumn.javaField.substring(0,1).toUpperCase() + ${treeParentColumn.javaField.substring(1)})##首字母大写
#set ($TreeNameJavaField = $treeNameColumn.javaField.substring(0,1).toUpperCase() + ${treeNameColumn.javaField.substring(1)})##首字母大写
        // 校验${treeParentColumn.columnComment}的有效性
        validateParent${simpleClassName}(null, ${saveReqVOVar}.get${TreeParentJavaField}());
        // 校验${treeNameColumn.columnComment}的唯一性
        validate${simpleClassName}${TreeNameJavaField}Unique(null, ${saveReqVOVar}.get${TreeParentJavaField}(), ${saveReqVOVar}.get${TreeNameJavaField}());

#end
        // 插入
#if ($voType == 10)
## TODO @puhui999：insert 也要加下 clean。万一前端乱传递，哈哈哈。这个就是 do 模式的缺点；（只在 do 模式下）；看看主子表，是不是也可能存在，insert 的时候；
        ${table.className}DO ${classNameVar} = BeanUtils.toBean(createReqVO, ${table.className}DO.class);
#end
        ${classNameVar}Mapper.insert(${classNameVar});
## 特殊：主子表专属逻辑（非 ERP 模式）
#if ( $subTables && $subTables.size() > 0 && $table.templateType != 11 )

        // 插入子表
#foreach ($subTable in $subTables)
#set ($index = $foreach.count - 1)
#set ($subSimpleClassName = $subSimpleClassNames.get($index))
#set ($subJoinColumn = $subJoinColumns.get($index))##当前 join 字段
#set ($SubJoinColumnName = $subJoinColumn.javaField.substring(0,1).toUpperCase() + ${subJoinColumn.javaField.substring(1)})##首字母大写
    #if ( $subTable.subJoinMany)
        create${subSimpleClassName}List(${classNameVar}.getId(), ${saveReqVOVar}.get${subSimpleClassNames.get($index)}s());
    #else
        create${subSimpleClassName}(${classNameVar}.getId(), ${saveReqVOVar}.get${subSimpleClassNames.get($index)}());
    #end
#end
#end
        // 返回
        return ${classNameVar}.getId();
    }

    @Override
## 特殊：主子表专属逻辑（非 ERP 模式）
#if ( $subTables && $subTables.size() > 0 && $table.templateType != 11 )
    @Transactional(rollbackFor = Exception.class)
#end
    public void update${simpleClassName}(${updateReqVOClass} ${updateReqVOVar}) {
        // 校验存在
        validate${simpleClassName}Exists(${updateReqVOVar}.getId());
## 特殊：树表专属逻辑
#if ( $table.templateType == 2 )
#set ($TreeParentJavaField = $treeParentColumn.javaField.substring(0,1).toUpperCase() + ${treeParentColumn.javaField.substring(1)})##首字母大写
#set ($TreeNameJavaField = $treeNameColumn.javaField.substring(0,1).toUpperCase() + ${treeNameColumn.javaField.substring(1)})##首字母大写
        // 校验${treeParentColumn.columnComment}的有效性
        validateParent${simpleClassName}(${updateReqVOVar}.getId(), ${updateReqVOVar}.get${TreeParentJavaField}());
        // 校验${treeNameColumn.columnComment}的唯一性
        validate${simpleClassName}${TreeNameJavaField}Unique(${updateReqVOVar}.getId(), ${updateReqVOVar}.get${TreeParentJavaField}(), ${updateReqVOVar}.get${TreeNameJavaField}());

#end
        // 更新
#if ($voType == 10)
        ${table.className}DO updateObj = BeanUtils.toBean(updateReqVO, ${table.className}DO.class);
        ${classNameVar}Mapper.updateById(updateObj);
#else
        ${classNameVar}Mapper.updateById(${updateReqVOVar});
#end
## 特殊：主子表专属逻辑（非 ERP 模式）
#if ( $subTables && $subTables.size() > 0 && $table.templateType != 11)

        // 更新子表
#foreach ($subTable in $subTables)
#set ($index = $foreach.count - 1)
#set ($subSimpleClassName = $subSimpleClassNames.get($index))
#set ($subJoinColumn = $subJoinColumns.get($index))##当前 join 字段
#set ($SubJoinColumnName = $subJoinColumn.javaField.substring(0,1).toUpperCase() + ${subJoinColumn.javaField.substring(1)})##首字母大写
    #if ( $subTable.subJoinMany)
        update${subSimpleClassName}List(${updateReqVOVar}.getId(), ${updateReqVOVar}.get${subSimpleClassNames.get($index)}s());
    #else
        update${subSimpleClassName}(${updateReqVOVar}.getId(), ${updateReqVOVar}.get${subSimpleClassNames.get($index)}());
    #end
#end
#end
    }

    @Override
## 特殊：主子表专属逻辑
#if ( $subTables && $subTables.size() > 0)
    @Transactional(rollbackFor = Exception.class)
#end
    public void delete${simpleClassName}(${primaryColumn.javaType} id) {
        // 校验存在
        validate${simpleClassName}Exists(id);
## 特殊：树表专属逻辑
#if ( $table.templateType == 2 )
#set ($ParentJavaField = $treeParentColumn.javaField.substring(0,1).toUpperCase() + ${treeParentColumn.javaField.substring(1)})##首字母大写
        // 校验是否有子${table.classComment}
        if (${classNameVar}Mapper.selectCountBy${ParentJavaField}(id) > 0) {
            throw exception(${simpleClassName_underlineCase.toUpperCase()}_EXITS_CHILDREN);
        }
#end
        // 删除
        ${classNameVar}Mapper.deleteById(id);
## 特殊：主子表专属逻辑
#if ( $subTables && $subTables.size() > 0)

        // 删除子表
#foreach ($subTable in $subTables)
#set ($index = $foreach.count - 1)
#set ($subSimpleClassName = $subSimpleClassNames.get($index))
#set ($subJoinColumn = $subJoinColumns.get($index))##当前 join 字段
#set ($SubJoinColumnName = $subJoinColumn.javaField.substring(0,1).toUpperCase() + ${subJoinColumn.javaField.substring(1)})##首字母大写
        delete${subSimpleClassName}By${SubJoinColumnName}(id);
#end
#end
    }

#if ( $table.templateType != 2 && $deleteBatchEnable)
    @Override
    ## 特殊：主子表专属逻辑
    #if ( $subTables && $subTables.size() > 0)
    @Transactional(rollbackFor = Exception.class)
    #end
    public void delete${simpleClassName}ListByIds(List<${primaryColumn.javaType}> ids) {
        // 校验存在
        validate${simpleClassName}Exists(ids);
        // 删除
        ${classNameVar}Mapper.deleteByIds(ids);
    ## 特殊：主子表专属逻辑
    #if ( $subTables && $subTables.size() > 0)

    // 删除子表
        #foreach ($subTable in $subTables)
            #set ($index = $foreach.count - 1)
            #set ($subSimpleClassName = $subSimpleClassNames.get($index))
            #set ($subJoinColumn = $subJoinColumns.get($index))##当前 join 字段
            #set ($SubJoinColumnName = $subJoinColumn.javaField.substring(0,1).toUpperCase() + ${subJoinColumn.javaField.substring(1)})##首字母大写
            delete${subSimpleClassName}By${SubJoinColumnName}s(ids);
        #end
    #end
    }

    private void validate${simpleClassName}Exists(List<${primaryColumn.javaType}> ids) {
        List<${table.className}DO> list = ${classNameVar}Mapper.selectByIds(ids);
        if (CollUtil.isEmpty(list) || list.size() != ids.size()) {
            throw exception(${simpleClassName_underlineCase.toUpperCase()}_NOT_EXISTS);
        }
    }
#end

    private void validate${simpleClassName}Exists(${primaryColumn.javaType} id) {
        if (${classNameVar}Mapper.selectById(id) == null) {
            throw exception(${simpleClassName_underlineCase.toUpperCase()}_NOT_EXISTS);
        }
    }

## 特殊：树表专属逻辑
#if ( $table.templateType == 2 )
#set ($TreeParentJavaField = $treeParentColumn.javaField.substring(0,1).toUpperCase() + ${treeParentColumn.javaField.substring(1)})##首字母大写
#set ($TreeNameJavaField = $treeNameColumn.javaField.substring(0,1).toUpperCase() + ${treeNameColumn.javaField.substring(1)})##首字母大写
    private void validateParent${simpleClassName}(Long id, Long ${treeParentColumn.javaField}) {
        if (${treeParentColumn.javaField} == null || ${simpleClassName}DO.${treeParentColumn_javaField_underlineCase.toUpperCase()}_ROOT.equals(${treeParentColumn.javaField})) {
            return;
        }
        // 1. 不能设置自己为父${table.classComment}
        if (Objects.equals(id, ${treeParentColumn.javaField})) {
            throw exception(${simpleClassName_underlineCase.toUpperCase()}_PARENT_ERROR);
        }
        // 2. 父${table.classComment}不存在
        ${simpleClassName}DO parent${simpleClassName} = ${classNameVar}Mapper.selectById(${treeParentColumn.javaField});
        if (parent${simpleClassName} == null) {
            throw exception(${simpleClassName_underlineCase.toUpperCase()}_PARENT_NOT_EXITS);
        }
        // 3. 递归校验父${table.classComment}，如果父${table.classComment}是自己的子${table.classComment}，则报错，避免形成环路
        if (id == null) { // id 为空，说明新增，不需要考虑环路
            return;
        }
        for (int i = 0; i < Short.MAX_VALUE; i++) {
            // 3.1 校验环路
            ${treeParentColumn.javaField} = parent${simpleClassName}.get${TreeParentJavaField}();
            if (Objects.equals(id, ${treeParentColumn.javaField})) {
                throw exception(${simpleClassName_underlineCase.toUpperCase()}_PARENT_IS_CHILD);
            }
            // 3.2 继续递归下一级父${table.classComment}
            if (${treeParentColumn.javaField} == null || ${simpleClassName}DO.${treeParentColumn_javaField_underlineCase.toUpperCase()}_ROOT.equals(${treeParentColumn.javaField})) {
                break;
            }
            parent${simpleClassName} = ${classNameVar}Mapper.selectById(${treeParentColumn.javaField});
            if (parent${simpleClassName} == null) {
                break;
            }
        }
    }

    private void validate${simpleClassName}${TreeNameJavaField}Unique(Long id, Long ${treeParentColumn.javaField}, String ${treeNameColumn.javaField}) {
        ${simpleClassName}DO ${classNameVar} = ${classNameVar}Mapper.selectBy${TreeParentJavaField}And${TreeNameJavaField}(${treeParentColumn.javaField}, ${treeNameColumn.javaField});
        if (${classNameVar} == null) {
            return;
        }
        // 如果 id 为空，说明不用比较是否为相同 id 的${table.classComment}
        if (id == null) {
            throw exception(${simpleClassName_underlineCase.toUpperCase()}_${treeNameColumn_javaField_underlineCase.toUpperCase()}_DUPLICATE);
        }
        if (!Objects.equals(${classNameVar}.getId(), id)) {
            throw exception(${simpleClassName_underlineCase.toUpperCase()}_${treeNameColumn_javaField_underlineCase.toUpperCase()}_DUPLICATE);
        }
    }

#end
    @Override
    public ${table.className}DO get${simpleClassName}(${primaryColumn.javaType} id) {
        return ${classNameVar}Mapper.selectById(id);
    }

## 特殊：树表专属逻辑（树不需要分页接口）
#if ( $table.templateType != 2 )
    @Override
    public PageResult<${table.className}DO> get${simpleClassName}Page(${sceneEnum.prefixClass}${table.className}PageReqVO pageReqVO) {
        return ${classNameVar}Mapper.selectPage(pageReqVO);
    }
#else
    @Override
    public List<${table.className}DO> get${simpleClassName}List(${sceneEnum.prefixClass}${table.className}ListReqVO listReqVO) {
        return ${classNameVar}Mapper.selectList(listReqVO);
    }
#end

## 特殊：主子表专属逻辑
#foreach ($subTable in $subTables)
#set ($index = $foreach.count - 1)
#set ($subSimpleClassName = $subSimpleClassNames.get($index))
#set ($simpleClassNameUnderlineCase = $simpleClassNameUnderlineCases.get($index))
#set ($subPrimaryColumn = $subPrimaryColumns.get($index))##当前 primary 字段
#set ($subJoinColumn = $subJoinColumns.get($index))##当前 join 字段
#set ($SubJoinColumnName = $subJoinColumn.javaField.substring(0,1).toUpperCase() + ${subJoinColumn.javaField.substring(1)})##首字母大写
#set ($subClassNameVar = $subClassNameVars.get($index))
    // ==================== 子表（$subTable.classComment） ====================

## 情况一：MASTER_ERP 时，需要分查询页子表
#if ( $table.templateType == 11 )
    @Override
    public PageResult<${subTable.className}DO> get${subSimpleClassName}Page(PageParam pageReqVO, ${subJoinColumn.javaType} ${subJoinColumn.javaField}) {
        return ${subClassNameVars.get($index)}Mapper.selectPage(pageReqVO, ${subJoinColumn.javaField});
    }

## 情况二：非 MASTER_ERP 时，需要列表查询子表
#else
    #if ( $subTable.subJoinMany )
    @Override
    public List<${subTable.className}DO> get${subSimpleClassName}ListBy${SubJoinColumnName}(${subJoinColumn.javaType} ${subJoinColumn.javaField}) {
        return ${subClassNameVars.get($index)}Mapper.selectListBy${SubJoinColumnName}(${subJoinColumn.javaField});
    }

    #else
    @Override
    public ${subTable.className}DO get${subSimpleClassName}By${SubJoinColumnName}(${subJoinColumn.javaType} ${subJoinColumn.javaField}) {
        return ${subClassNameVars.get($index)}Mapper.selectBy${SubJoinColumnName}(${subJoinColumn.javaField});
    }

    #end
#end
## 情况一：MASTER_ERP 时，支持单个的新增、修改、删除操作
#if ( $table.templateType == 11 )
    @Override
    public ${subPrimaryColumn.javaType} create${subSimpleClassName}(${subTable.className}DO ${subClassNameVar}) {
## 特殊：一对一时，需要保证只有一条，不能重复插入
#if ( !$subTable.subJoinMany)
        // 校验是否已经存在
        if (${subClassNameVars.get($index)}Mapper.selectBy${SubJoinColumnName}(${subClassNameVar}.get${SubJoinColumnName}()) != null) {
            throw exception(${simpleClassNameUnderlineCase.toUpperCase()}_EXISTS);
        }
        // 插入
#end
        ${subClassNameVars.get($index)}Mapper.insert(${subClassNameVar});
        return ${subClassNameVar}.getId();
    }

    @Override
    public void update${subSimpleClassName}(${subTable.className}DO ${subClassNameVar}) {
        // 校验存在
        validate${subSimpleClassName}Exists(${subClassNameVar}.getId());
        // 更新
        ${subClassNameVar}.clean(); // 解决更新情况下：updateTime 不更新
        ${subClassNameVars.get($index)}Mapper.updateById(${subClassNameVar});
    }

    @Override
    public void delete${subSimpleClassName}(${subPrimaryColumn.javaType} id) {
        // 删除
        ${subClassNameVars.get($index)}Mapper.deleteById(id);
    }

#if ($deleteBatchEnable)
	@Override
	public void delete${subSimpleClassName}ListByIds(List<${subPrimaryColumn.javaType}> ids) {
        // 删除
        ${subClassNameVars.get($index)}Mapper.deleteByIds(ids);
	}
#end

    @Override
    public ${subTable.className}DO get${subSimpleClassName}(${subPrimaryColumn.javaType} id) {
        return ${subClassNameVars.get($index)}Mapper.selectById(id);
    }

    private void validate${subSimpleClassName}Exists(${subPrimaryColumn.javaType} id) {
        if (${subClassNameVar}Mapper.selectById(id) == null) {
            throw exception(${simpleClassNameUnderlineCase.toUpperCase()}_NOT_EXISTS);
        }
    }

## 情况二：非 MASTER_ERP 时，支持批量的新增、修改操作
#else
    #if ( $subTable.subJoinMany)
    private void create${subSimpleClassName}List(${primaryColumn.javaType} ${subJoinColumn.javaField}, List<${subTable.className}DO> list) {
        list.forEach(o -> o.set${SubJoinColumnName}(${subJoinColumn.javaField}).clean());
        ${subClassNameVars.get($index)}Mapper.insertBatch(list);
    }

    private void update${subSimpleClassName}List(${primaryColumn.javaType} ${subJoinColumn.javaField}, List<${subTable.className}DO> list) {
	    list.forEach(o -> o.set${SubJoinColumnName}(${subJoinColumn.javaField}).clean());
	    List<${subTable.className}DO> oldList = ${subClassNameVar}Mapper.selectListBy${SubJoinColumnName}(${subJoinColumn.javaField});
	    List<List<${subTable.className}DO>> diffList = diffList(oldList, list, (oldVal, newVal) -> {
            boolean same = ObjectUtil.equal(oldVal.getId(), newVal.getId());
            if (same) {
                newVal.setId(oldVal.getId()).clean(); // 解决更新情况下：updateTime 不更新
            }
            return same;
	    });

	    // 第二步，批量添加、修改、删除
	    if (CollUtil.isNotEmpty(diffList.get(0))) {
	        ${subClassNameVar}Mapper.insertBatch(diffList.get(0));
	    }
	    if (CollUtil.isNotEmpty(diffList.get(1))) {
	        ${subClassNameVar}Mapper.updateBatch(diffList.get(1));
	    }
	    if (CollUtil.isNotEmpty(diffList.get(2))) {
	        ${subClassNameVar}Mapper.deleteByIds(convertList(diffList.get(2), ${subTable.className}DO::getId));
	    }
    }

    #else
    private void create${subSimpleClassName}(${primaryColumn.javaType} ${subJoinColumn.javaField}, ${subTable.className}DO ${subClassNameVar}) {
        if (${subClassNameVar} == null) {
            return;
        }
        ${subClassNameVar}.set$SubJoinColumnName(${subJoinColumn.javaField});
        ${subClassNameVars.get($index)}Mapper.insert(${subClassNameVar});
    }

    private void update${subSimpleClassName}(${primaryColumn.javaType} ${subJoinColumn.javaField}, ${subTable.className}DO ${subClassNameVar}) {
        if (${subClassNameVar} == null) {
			return;
        }
        ${subClassNameVar}.set$SubJoinColumnName(${subJoinColumn.javaField}).clean();// 解决更新情况下：updateTime 不更新
        ${subClassNameVars.get($index)}Mapper.insertOrUpdate(${subClassNameVar});
    }

    #end
#end
    private void delete${subSimpleClassName}By${SubJoinColumnName}(${primaryColumn.javaType} ${subJoinColumn.javaField}) {
        ${subClassNameVars.get($index)}Mapper.deleteBy${SubJoinColumnName}(${subJoinColumn.javaField});
    }

#if ( $table.templateType != 2 && $deleteBatchEnable)
	private void delete${subSimpleClassName}By${SubJoinColumnName}s(List<${primaryColumn.javaType}> ${subJoinColumn.javaField}s) {
        ${subClassNameVars.get($index)}Mapper.deleteBy${SubJoinColumnName}s(${subJoinColumn.javaField}s);
	}
#end

#end
}