package {{packageName}}.{{entity.module}}.service;

import java.io.Serializable;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
import java.util.Collection;
import java.math.BigInteger;
import java.math.BigDecimal;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.scheduling.annotation.Async;
import org.springframework.util.ObjectUtils;
import com.alibaba.fastjson.JSONObject;
import org.springframework.cache.annotation.CacheEvict;
import com.baomidou.dynamic.datasource.annotation.DS;
import net.ibizsys.central.util.ISearchContextDTO;
import net.ibizsys.model.dataentity.action.IPSDEAction;
import net.ibizsys.model.dataentity.ds.IPSDEDataSet;
import net.ibizsys.central.plugin.boot.core.service.IMPService;
import net.ibizsys.central.plugin.boot.core.helper.CachedBeanCopier;
import net.ibizsys.central.plugin.boot.core.helper.SpringContextHolder;
import net.ibizsys.central.dataentity.IDataEntityRuntimeContext;
import {{packageName}}.{{entity.module}}.domain.{{entity.codeName}};
import {{packageName}}.{{entity.module}}.filter.{{entity.codeName}}SearchContext;
import {{packageName}}.{{entity.module}}.mapper.{{entity.codeName}}Mapper;
{{#entity.relEntities}}
import {{packageName}}.{{module}}.domain.{{codeName}};
{{#neq storage "NONE"}}
import {{packageName}}.{{module}}.service.{{codeName}}Service;
{{/neq}}
{{/entity.relEntities}}

{{#dsName}}
@DS("{{entity.dataSource}}")
{{/dsName}}
public interface {{entity.codeName}}Service extends IMPService<{{entity.codeName}}, {{entity.codeName}}SearchContext,{{entity.codeName}}Mapper> {

    @Override
    default String getDataEntityId() {
        return "PSMODULES/{{entity.psSystemModule.codeName}}/PSDATAENTITIES/{{entity.codeName}}.json";
    }

    default {{entity.codeName}}Service getProxyService() {
        return SpringContextHolder.getBean(this.getClass());
    }

    default boolean create({{entity.codeName}} dto) throws Throwable {
        return IMPService.super.create(dto);
    }
    default boolean onCreate({{entity.codeName}} dto) throws Throwable {
        return IMPService.super.onCreate(dto);
    }

    {{#entity.enableEntityCache}}
    @CacheEvict(value = "{{lowerCase entity.codeName}}", allEntries = true)
    {{/entity.enableEntityCache}}
    default boolean update({{entity.codeName}} dto) throws Throwable {
        return IMPService.super.update(dto);
    }

    {{#entity.enableEntityCache}}
    @CacheEvict(value = "{{lowerCase entity.codeName}}", allEntries = true)
    {{/entity.enableEntityCache}}
    default boolean onUpdate({{entity.codeName}} dto) throws Throwable {
        return IMPService.super.onUpdate(dto);
    }

    {{#entity.enableEntityCache}}
    @CacheEvict(value = "{{lowerCase entity.codeName}}", allEntries = true)
    {{/entity.enableEntityCache}}
    default boolean remove({{entity.keyField.type.java}} key) throws Throwable {
        return IMPService.super.remove(key);
    }

    {{#entity.enableEntityCache}}
    @CacheEvict(value = "{{lowerCase entity.codeName}}", allEntries = true)
    {{/entity.enableEntityCache}}
    default boolean onRemove({{entity.keyField.type.java}} key) throws Throwable {
        return IMPService.super.onRemove(key);
    }

    {{#entity.enableEntityCache}}
    @CacheEvict(value = "{{lowerCase entity.codeName}}", allEntries = true)
    {{/entity.enableEntityCache}}
    default boolean remove(List keys) throws Throwable {
        return IMPService.super.remove(keys);
    }

    {{#entity.enableEntityCache}}
    @CacheEvict(value = "{{lowerCase entity.codeName}}", allEntries = true)
    {{/entity.enableEntityCache}}
    default boolean onRemove(List keys) throws Throwable {
        return IMPService.super.onRemove(keys);
    }

    default {{entity.codeName}} get({{entity.keyField.type.java}} key) throws Throwable {
        return IMPService.super.get(key);
    }

    default {{entity.codeName}} onGet({{entity.keyField.type.java}} key) throws Throwable {
        return IMPService.super.onGet(key);
    }

    default {{entity.codeName}} getDraft({{entity.codeName}} dto) throws Throwable {
        return IMPService.super.getDraft(dto);
    }

    default {{entity.codeName}} onGetDraft({{entity.codeName}} dto) throws Throwable {
        return IMPService.super.onGetDraft(dto);
    }

    default Integer checkKey({{entity.codeName}} dto) throws Throwable {
        return IMPService.super.checkKey(dto);
    }

    default Integer onCheckKey({{entity.codeName}} dto) throws Throwable {
        return IMPService.super.onCheckKey(dto);
    }

    {{#entity.enableEntityCache}}
    @CacheEvict(value = "{{lowerCase entity.codeName}}", allEntries = true)
    {{/entity.enableEntityCache}}
    default boolean save({{entity.codeName}} dto) throws Throwable {
        return IMPService.super.save(dto);
    }

    {{#entity.enableEntityCache}}
    @CacheEvict(value = "{{lowerCase entity.codeName}}", allEntries = true)
    {{/entity.enableEntityCache}}
    default boolean onSave({{entity.codeName}} dto) throws Throwable {
        return IMPService.super.onSave(dto);
    }

    {{#each entity.extActions}}
    default {{outParam}} {{camelCase codeName}}({{inParam}} {{inParamName}})  throws Throwable {
        {{#if voidReturn}}
        IMPService.super.callAction("{{codeName}}",{{inParamName}});
        return {{inParamName}};
        {{else}}
        IMPService.super.beforeAction("{{codeName}}",{{inParamName}});
        {{outParam}} rt = ({{outParam}})IMPService.super.forwardAction("{{codeName}}",{{inParamName}});
        if(rt!=null)
            IMPService.super.afterAction("{{codeName}}",rt);
        return rt;
        {{/if}}
    }

    default {{outParam}} on{{pascalCase codeName}}({{inParam}} {{inParamName}})  throws Throwable {
        {{#if voidReturn}}
        IMPService.super.onRealAction("{{codeName}}",{{inParamName}});
        return {{inParamName}};
        {{else}}
        return ({{outParam}})IMPService.super.onRealAction("{{codeName}}",{{inParamName}});
        {{/if}}
    }

    {{/each}}

    {{#entity.dataSets}}
    default Page<{{entity.codeName}}> fetch{{pascalCase codeName}}({{entity.codeName}}SearchContext dto) throws Throwable {
        IMPService.super.beforeFetch("{{codeName}}",dto);
        return (Page) IMPService.super.forwardFetch("{{name}}",dto);
    }

    default Page<{{entity.codeName}}> onFetch{{pascalCase codeName}}({{entity.codeName}}SearchContext dto) throws Throwable {
        return (Page) IMPService.super.onRealFetch("{{name}}",dto);
    }

    {{/entity.dataSets}}

    {{#entity.hasReferences}}
    default void fillParentData({{entity.codeName}} et) {
        {{#each entity.references as |reference|}}
        {{#gt reference.relFieldCount 1}}
        if(!ObjectUtils.isEmpty(et.get{{pascalCase reference.fkField.codeName}}())) {
            {{reference.entityCodeName}} {{camelCase reference.entityCodeName}} = et.get{{pascalCase reference.codeName}}();
            if(!ObjectUtils.isEmpty({{camelCase reference.entityCodeName}})) {
                {{#each reference.fields as |field|}}
                {{#neq field.dataType 'PICKUP'}}
                et.set{{pascalCase field.codeName}}({{camelCase reference.entityCodeName}}.get{{pascalCase field.refFieldCodeName}}());
                {{/neq}}
                {{/each}}
            }
        }
        {{/gt}}
        {{/each}}
    }
    {{/entity.hasReferences}}

    default List<{{entity.codeName}}> getByEntities(List<{{entity.codeName}}> entities) {
        return this.getBaseMapper().selectEntities(entities);
    }

    {{#entity.references}}
    default List<{{entity.codeName}}> selectBy{{pascalCase fkField.codeName}}({{fkField.type.java}} {{camelCase fkField.codeName}}) {
        return this.getBaseMapper().selectBy{{pascalCase fkField.codeName}}({{camelCase fkField.codeName}});
    }
    {{/entity.references}}
}