package cc.smtweb.system.bpm.web.engine.dynPage;

import cc.smtweb.framework.core.cache.AbstractCache;
import cc.smtweb.framework.core.cache.CacheManager;
import cc.smtweb.framework.core.common.R;
import cc.smtweb.framework.core.common.SwEnum;
import cc.smtweb.framework.core.common.SwMap;
import cc.smtweb.framework.core.db.DbEngine;
import cc.smtweb.framework.core.db.EntityDao;
import cc.smtweb.framework.core.db.cache.ModelTableCache;
import cc.smtweb.framework.core.db.impl.DefaultEntity;
import cc.smtweb.framework.core.db.jdbc.IDbWorker;
import cc.smtweb.framework.core.db.vo.ModelField;
import cc.smtweb.framework.core.db.vo.ModelIndex;
import cc.smtweb.framework.core.db.vo.ModelTable;
import cc.smtweb.framework.core.exception.BizException;
import cc.smtweb.framework.core.mvc.service.TreeHelper;
import cc.smtweb.framework.core.util.StringUtil;
import cc.smtweb.system.bpm.web.design.form.define.PageDataset;
import cc.smtweb.system.bpm.web.design.form.define.PageDatasetFilter;
import org.apache.commons.lang3.StringUtils;

import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by Akmm at 2022/4/21 17:53
 * 保存指定数据集操作
 * 入参：{pageId, data:}
 */
public class DynPageSaveHandler extends AbstractDynPageHandler {
    private Map<String, List<DefaultEntity>> mapTreeBean = new HashMap<>();

    /**
     * 保存指定数据集操作，入参：{pageId,dataset:"", data:{form:{},list: {total:0,rows:[]}}, filter:{}}
     */
    public R saveOne() {
        //数据集
        String dbName = params.readString("dataset");
        SwMap filter = params.readMap("filter");
        //待保存数据
        SwMap data = params.readMap("data");
        if (data == null) throw new BizException("没有收到待保存的的数据：" + dbName + "！");
        //对应的数据集定义
        PageDataset pageDataSet = findDataset(dbName);
        if (pageDataSet == null) throw new BizException("没有找到指定的的数据集定义：" + dbName + "！");

        //读取待保存的bean
        DefaultEntity bean = readBeanFromPage(pageDataSet, data.readMap("form"));
        if (filter != null && bean.isNew()) {//有过滤条件，将关联的值设上
            setLinkValue(pageDataSet, bean, f -> filter.get(f.name));
        }
        checkBean(bean);

        DbEngine.getInstance().doTrans(new IDbWorker() {
            @Override
            public void work() {
                saveBean(bean);
            }

            @Override
            public void doAfterDbCommit() {
                afterCommit(bean);
            }

            @Override
            public void doAfterDbRollback() {
                afterRollback(bean);
            }
        });
        bean.removeStatus();
        return R.success(DynRetBean.createBean(bean.getData()));
    }

    /**
     * 保存对象，所有数据集数据对象,{ ds1: {form:{},list:{total:0,rows:[]}}}
     *
     * @return
     */
    public R saveAll() {
        SwMap data = params.readMap("data");
        if (data == null) throw new BizException("没有收到待保存的的数据！");
        SwMap filter = params.readMap("filter");

        Map<String, DefaultEntity> map = new LinkedHashMap<>();
        for (PageDataset pageDataSet : datasets.list) {
            //非表单编辑，不管
            if (!pageDataSet.canEdit || !SwEnum.DatasetType.FORM.value.equals(pageDataSet.type)) continue;
            SwMap dsData = data.readMap(pageDataSet.name);
            if (dsData == null) continue;

            //读取待保存的bean
            DefaultEntity bean = readBeanFromPage(pageDataSet, dsData.readMap("form"));
            map.put(pageDataSet.name, bean);
            SwMap dsFilter = filter.readMap(pageDataSet.name);
            if (dsFilter != null && bean.isNew()) {//有过滤条件，将关联的值设上
                setLinkValue(pageDataSet, bean, f -> {
                    //link类型，去取另一个dataset的值
                    if (SwEnum.FilterType.LINK.value.equals(f.type)) {
                        DefaultEntity lv = map.get(f.linkDb);
                        if (lv != null) return lv.get(f.linkField);
                    }
                    return dsFilter.get(f.name);
                });
            }
            checkBean(bean);
        }
        DbEngine.getInstance().doTrans(new IDbWorker() {
            @Override
            public void work() {
                for (DefaultEntity bean : map.values()) {
                    saveBean(bean);
                }
            }

            @Override
            public void doAfterDbCommit() {
                for (DefaultEntity bean : map.values()) {
                    afterCommit(bean);
                }
            }

            @Override
            public void doAfterDbRollback() {
                for (DefaultEntity bean : map.values()) {
                    afterRollback(bean);
                }
            }
        });
        Map<String, DynRetBean> mapRet = new HashMap<>(map.size());
        for (Map.Entry<String, DefaultEntity> entry : map.entrySet()) {
            entry.getValue().getData().remove(DefaultEntity.statusKey);
            mapRet.put(entry.getKey(), DynRetBean.createBean(entry.getValue().getData()));
        }
        return R.success(mapRet);
    }

    /**
     * 从页面获取待保存的bean
     *
     * @param pageDataSet
     * @param data
     * @return
     */
    protected DefaultEntity readBeanFromPage(PageDataset pageDataSet, SwMap data) {
        ModelTable table = ModelTableCache.getInstance().get(pageDataSet.masterTable);
        if (table == null) throw new BizException("没有找到待保存的表定义：" + pageDataSet.name);

        long id = data.readLong(table.getIdField());
        boolean isNew = data.readBool(DefaultEntity.statusKey) || id <= 0L;

        EntityDao<DefaultEntity> dao = DbEngine.getInstance().findDao(table.getName());
        DefaultEntity bean;
        if (isNew) {
            bean = dao.createBean(us.getUserId());
            //暂时不考虑list保存的情况
            bean.getData().putAll(data);
            if (bean.getEntityId() <= 0L) bean.setEntityId(DbEngine.getInstance().nextId());
        } else {
            bean = dao.queryEntity(id);
            if (bean == null) {
                throw new BizException("没有找到待保存的记录：" + table.getName() + "." + id);
            }
            //暂时不考虑list保存的情况
            bean.getData().putAll(data);
        }

        return bean;
    }

    /**
     * 保存校验
     *
     * @param bean
     */
    protected void checkBean(DefaultEntity bean) {
        ModelTable table = ModelTableCache.getInstance().getByName(bean.getTableName());
        for (ModelField field : table.getFields()) {
            String value = bean.getStr(field.getName());
            //非空校验
            if (field.isNotNull() && StringUtils.isEmpty(value)) {
                throw new BizException("字段不允许为空：" + field.getTitle());
            }

            //长度校验
            if (StringUtils.isNotEmpty(value)) {
                int len = SwEnum.DataType.instance.getByValue(field.getDataType()).dataLength;
                if (len > 0 && StringUtil.getStrLenB(value) > len) {
                    throw new BizException("字段值超长：" + field.getTitle());
                }
            }
        }
        //唯一键校验
        EntityDao<DefaultEntity> dao = DbEngine.getInstance().findDao(bean.getTableName());
        for (ModelIndex mi : table.getIndexes()) {
            if (mi.isUnique()) {
                dao.checkUnique(bean, mi.getFields().split(","));
            }
        }
    }

    protected void saveBean(DefaultEntity bean) {
        final String tableName = bean.getTableName();
        EntityDao<DefaultEntity> dao = DbEngine.getInstance().findDao(tableName);
        if (bean.isNew()) {
            dao.insertEntity(bean);
        } else {
            ModelTable table = ModelTableCache.getInstance().getByName(tableName);
            ModelField field = table.findFieldByType(SwEnum.FieldType.UPDATE_USER.value);
            if (field != null) bean.put(field.getName(), us.getUserId());

            dao.updateEntity(bean);
            if (table.getType() == SwEnum.TableType.TYPE_TREE.value) {
                List<DefaultEntity> listTreeBean = TreeHelper.getTreeHelper(tableName).resetTreeLevel(bean);
                mapTreeBean.put(tableName, listTreeBean);
            }
        }
    }

    protected void afterCommit(DefaultEntity bean) {
        final String tableName = bean.getTableName();
        ModelTable table = ModelTableCache.getInstance().getByName(tableName);
        if (table.isNeedCache()) {
            AbstractCache<DefaultEntity> cache = CacheManager.getIntance().getCache(tableName);
            List<DefaultEntity> listTreeBean = mapTreeBean.get(tableName);
            //树型表，父亲改变了，要多处理下缓存；还有个东东：级次码
            if (listTreeBean != null && !listTreeBean.isEmpty()) {
                for (DefaultEntity b : listTreeBean) {
                    cache.put(b);
                }
            } else {
                cache.put(bean);
            }
        }
    }

    protected void afterRollback(DefaultEntity bean) {
        final String tableName = bean.getTableName();
        ModelTable table = ModelTableCache.getInstance().getByName(tableName);
        if (table.isNeedCache()) {
            AbstractCache<DefaultEntity> cache = CacheManager.getIntance().getCache(tableName);
            cache.reset(bean);
        }
    }

    //将关联的值设上
    protected void setLinkValue(PageDataset pageDataSet, DefaultEntity bean, IGetValue iGetValue) {
        ModelTable table = ModelTableCache.getInstance().getByName(bean.getTableName());
        for (PageDatasetFilter f : pageDataSet.filters) {
            String v = bean.getStr(f.field);
            //有值，就不管
            if (v != null && !v.equals(table.findField(f.field).getDefaultValue())) continue;

            if (SwEnum.FilterType.CONST.value.equals(f.type)) {//常量
                bean.put(f.field, f.value);
            } else if (SwEnum.FilterType.PARAM.value.equals(f.type)) {//参数
                bean.put(f.field, f.value);
            } else if (SwEnum.FilterType.LINK.value.equals(f.type)) {//参数
                Object value = iGetValue.getValue(f);
                if (value != null) {
                    bean.put(f.field, value);
                }
            }
        }
    }

    interface IGetValue {
        Object getValue(PageDatasetFilter f);
    }
}
