package cc.smtweb.framework.core.mvc.service;

import cc.smtweb.framework.core.cache.SessionCache;
import cc.smtweb.framework.core.cache.SessionCacheFactory;
import cc.smtweb.framework.core.common.R;
import cc.smtweb.framework.core.common.SwMap;
import cc.smtweb.framework.core.db.DbEngine;
import cc.smtweb.framework.core.mvc.service.list.FooterField;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

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

import static cc.smtweb.framework.core.common.SwConsts.TOTAL_KEY;

/**
 * Created by Akmm at 2022/3/2 19:44
 * 列表服务
 */
@Slf4j
public abstract class AbstractListHandler extends AbstractHandler {
    protected static String KEY_SQLPARA = "query-sqlPara";
    protected static String KEY_SQLPARA_SUM = "query-sqlPara-sum";
    protected static String KEY_PARAMS = "query-params";

    private SessionCache sessionCache;

    protected String getCompId() {
        return this.getClass().getSimpleName();
    }

    protected <T> T getCache(String key) {
        if (sessionCache == null)
            sessionCache = SessionCacheFactory.getInstance().getUserCache(us.getUserId());
        return sessionCache.get(getCompId() + "." + key);
    }

    protected void setCache(String key, Object v) {
        if (sessionCache == null)
            sessionCache = SessionCacheFactory.getInstance().getUserCache(us.getUserId());
        sessionCache.put(getCompId() + "." + key, v);
    }

    protected void removeCache(String key) {
        if (sessionCache == null)
            sessionCache = SessionCacheFactory.getInstance().getUserCache(us.getUserId());
        sessionCache.remove(getCompId() + "." + key);
    }

    public R data() {
        return R.success(buildListData());
    }

    /**
     * 导出excel
     * @return R:{ file: fileName@@filePath }
     */
    public R exportExcel() {
        return R.success(buildListData());
    }

    public SwListData buildListData() {
        List<SwMap> listData;
        SqlPara sqlPara = buildDataSql();

        String sort = params.readString("sort");
        String order = params.readString("order");
        String sql;
        if (StringUtils.isEmpty(sort)) sql = sqlPara.sql;
        else {
            sql = "select ar.* from (" + sqlPara.sql + ") ar order by ar." + sort + " " + order;
            if (StringUtils.isNotEmpty(getPkFieldName())) {
                sql += "," + getPkFieldName();
            }
        }

        listData = queryData(sql, sqlPara);

        afterQuery(listData);
        if (sqlPara.page <= 1) {
            return SwListData.create(listData, sqlPara.rows);
        } else {
            return SwListData.create(listData);
        }
    }

    protected List<SwMap> queryData(String sql, SqlPara sqlPara) {
        sqlPara.rows = params.readInt("rows", 0);
        sqlPara.page = params.readInt("page", 1);


        if (sqlPara.rows == 0) {
            return DbEngine.getInstance().query(sql, SwMap.class, sqlPara.paras);
        } else {
            //查分页数据
            return DbEngine.getInstance().pagedQuery(sql, SwMap.class, (sqlPara.page - 1) * sqlPara.rows, sqlPara.rows, sqlPara.paras);
        }
    }

    protected SqlPara buildSumSqlPara() {
        SqlPara sqlPara = getCache(KEY_SQLPARA);
        if (sqlPara == null) return null;

        List<FooterField> footerFields = getFooterFields();
        StringBuilder sql = new StringBuilder(128);
        sql.append("select count(1) " + TOTAL_KEY);
        for (FooterField cn : footerFields) {
            if (!FooterField.STATIC_TEXT.equals(cn.type)) {
                if (FooterField.SUM_TYPE_COUNT_ALL.equals(cn.type)) {
                    sql.append(",COUNT(");
                } else if (FooterField.SUM_TYPE_SUM_NUM.equals(cn.type)) {
                    sql.append(",SUM(");
                } else {
                    sql.append(",").append(cn.type).append("(");
                }
                if (FooterField.SUM_TYPE_COUNT.equals(cn.type))
                    sql.append("distinct ");
                sql.append(cn.field).append(") ").append(cn.field);
            }
        }
        sql.append(" from (").append(sqlPara.getSqlNoOrderBy()).append(") xxxxxz");

        return new SqlPara(sql.toString(), sqlPara.paras);
    }

    public R getTotal() {
        try {
            SqlPara sqlParaSum = getCache(KEY_SQLPARA_SUM);
            if (sqlParaSum == null) {
                Map<String, Object> map = getCache(KEY_PARAMS);
                if (map != null) params.putAll(map);
                sqlParaSum = buildSumSqlPara();
            }
            if (sqlParaSum == null) return R.success();
            setCache(KEY_SQLPARA_SUM, sqlParaSum);

            SwMap mapFooter = DbEngine.getInstance().queryEntity(sqlParaSum.sql, SwMap.class, sqlParaSum.paras);

            SwMap r = new SwMap();
            r.put("total", mapFooter.get(TOTAL_KEY));
            r.put("footer", mapFooter);
            return R.success(r);
        } catch (Exception e) {
            return R.error("计算合计失败！", e);
        }
    }

    protected <T extends SqlPara> T buildDataSql() {
        //从缓存里看看有没有保存的sql缓存；
        T sqlParaInCache = getCache(KEY_SQLPARA);  //缓存里面的对象；
        boolean query = sqlParaInCache == null || params.readBool("query");
        if (!query) {
            Map<String, Object> map = getCache(KEY_PARAMS);
            if (map == null) query = true;
            else {
                Map<String, Object> params = getCachedParams();
                if (params.size() > map.size()) query = true;//本次参数更多
                else {
                    for (String key : params.keySet()) {
                        Object v = map.get(key);
                        String cv = v != null && StringUtils.isNotEmpty(v.toString()) ? v.toString(): "";
                        v = params.get(key);
                        String rv = v != null && StringUtils.isNotEmpty(v.toString()) ? v.toString(): "";
                        if (!cv.equals(rv)) {
                            query = true;
                            break;
                        }
                    }
                }
            }
        }
        T sqlPara = null;
        if (query) {//新查询
            //缓存里面没有对象，重新构建查询条件，重新计算汇总数；
            buildParam();//构造过滤条件，设默认值
            sqlPara = buildSqlPara();  //重新构建查询对象；
            removeCache(KEY_SQLPARA_SUM);

            setCache(KEY_SQLPARA, sqlPara);
            setCache(KEY_PARAMS, getCachedParams());//不缓存页码之类的东东，避免下次请求时，页码又回去了
        } else {
            sqlPara = sqlParaInCache;

            Map<String, Object> map = getCache(KEY_PARAMS);
            if (map != null) params.putAll(map);
        }
        return sqlPara;
    }

    /**
     * 构造过滤条件，设默认值
     *
     * @throws Exception
     */
    protected void buildParam() {

    }

    /**
     * sql主键字段，用于点击表头排序时保证排序记录唯一性
     *
     * @return
     */
    protected String getPkFieldName() {
        return null;
    }

    protected void afterQuery(List<SwMap> listData) {
    }

    protected abstract <T extends SqlPara> T buildSqlPara();

    //构建合计字段
    private List<FooterField> getFooterFields() {
        List<FooterField> footerFields = new ArrayList<>();
        buildFooterFields(footerFields);
        return footerFields;
    }

    protected void buildFooterFields(List<FooterField> footer) {
    }

    protected Map<String, Object> getCachedParams() {
        Map<String, Object> map = new HashMap<>();
        map.putAll(params);
        map.remove("page");
        map.remove("rows");
        map.remove("sort");
        map.remove("order");
        map.remove("tokenkey");
        map.remove("tokenval");
        map.remove("_v");
        map.remove("_dn");
        map.remove("_sk");
        map.remove("_skw");
        map.remove("_tk");
        map.remove("_sb");
        map.remove("__exp_model");
        map.remove("model");
        map.remove("data");
        return map;
    }
}
