package com.boman.web.core.service.select;

import com.alibaba.fastjson.JSONObject;
import com.boman.common.redis.RedisKey;
import com.boman.domain.GenTable;
import com.boman.domain.GenTableColumn;
import com.boman.domain.constant.MaskConstant;
import com.boman.domain.dto.FormDataDto;
import com.boman.domain.dto.QueryBySqlDto;
import com.boman.web.core.mapper.StandardMapper;
import com.boman.web.core.service.TableServiceCmdService;
import com.boman.web.core.utils.ColumnUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

import static com.boman.common.core.utils.obj.ObjectUtils.isEmpty;
import static com.boman.common.core.utils.obj.ObjectUtils.requireNonNull;
import static com.boman.web.core.utils.ColumnUtils.filterData;
import static com.boman.web.core.utils.HandlerFormDataUtils.*;

/**
 * @author shiqian
 * @date 2021年03月29日 10:22
 **/
@Service
public class BaseSelectServiceImpl implements IBaseSelectService {

    private static final Logger LOGGER = LoggerFactory.getLogger(BaseSelectServiceImpl.class);

    @Autowired
    private StandardMapper mapper;
    @Autowired
    private TableServiceCmdService cmdService;


    /**
     * 功能描述: 根据条件查询
     *
     * @param tableName     tableName
     * @param condition     原始查询条件
     * @param packCondition 封装的查询条件
     * @param showData      前台需要查询的列
     * @param dto           orderBy limit offset
     * @return java.util.List<com.alibaba.fastjson.JSONObject>
     */
    @Override
    public List<JSONObject> selectByCondition(String tableName, JSONObject condition, JSONObject packCondition, List<String> showData, FormDataDto dto) {
        requireNonNull(tableName, "表名为空");
        requireNonNull(showData, String.format("此表 = [%s], 无列表可展示字段", tableName));
        String orderBy = requireNonNull(dto.getOrderBy(), "order by is empty");
        return mapper.selectByCondition(tableName, condition, packCondition, showData, orderBy, dto.getLimit(), dto.getOffset());
    }

    @Override
    public List<JSONObject> selectByLeftJoinCondition(QueryBySqlDto queryBySql, JSONObject packCondition, JSONObject condition, List<String> showData) {
        String primaryTableName = queryBySql.getPrimaryTableName() ,deputyTableName = queryBySql.getDeputyTableName();
        String primaryTableNameRelKey = queryBySql.getPrimaryTableNameRelKey(), deputyTableNameRelKey = queryBySql.getDeputyTableNameRelKey();
        requireNonNull(primaryTableName, String.format("tableName = [%s] , 此表不存在", primaryTableName));
        requireNonNull(deputyTableName, String.format("tableName = [%s] , 此表不存在", deputyTableName));
        requireNonNull(primaryTableNameRelKey, String.format("主表和子表 关联字段名称不存在, name = [%s]", primaryTableNameRelKey));
        requireNonNull(deputyTableNameRelKey, String.format("子表和主表 关联字段名称不存在, name = [%s]", deputyTableNameRelKey));
        requireNonNull(showData, String.format("子表和主表 关联字段名称不存在, name = [%s]", deputyTableNameRelKey));
        String orderBy = requireNonNull(queryBySql.getOrderBy(), "order by is empty");

        return mapper.selectByLeftJoinCondition(queryBySql, packCondition, condition, showData, orderBy, queryBySql.getLimit(), queryBySql.getOffset());
    }

    /**
     * 功能描述: 根据tableName和map(属性名和属性值)进行查查
     *
     * @param tableName tableName
     * @param param     属性名和属性值
     * @return java.util.List<com.alibaba.fastjson.JSONObject>
     */
    @Override
    public List<JSONObject> getByMap(String tableName, JSONObject param) {
        requireNonNull(tableName, "表名为空");

        // 判断condition中列是否都在此table中
        GenTable gent = cmdService.getTableFromRedisByTableName(RedisKey.TABLE_INFO, tableName);
        List<GenTableColumn> columns = gent.getColumns();
        ColumnUtils.checkColumn(param, columns);
        JSONObject packColCondition = ColumnUtils.packColCondition(columns, param);
        List<JSONObject> result = mapper.getByMap(tableName, packColCondition, param, false);

        List<String> showData = filterData(columns, 4, null, MaskConstant.LIST_VISIBLE::equals);
        // 查询时为null的列不显示的处理
        handleNullColumnValue(result, showData);
        handleBlob(result, gent.getIsContainsBlob());
        handleDateTimeForQueryList(result, gent.getColumns());
        handleDictForQueryList(result, gent.getColumns());
        handleFkForQueryList(result, gent.getColumns());

        return result;
    }


    /**
     * 功能描述: 根据tableName和map(属性名和属性值)进行查查
     *
     * @param tableName tableName
     * @param param     属性名和属性值
     * @return com.alibaba.fastjson.JSONObject
     */
    @Override
    public JSONObject getOneByMap(String tableName, JSONObject param) {
        requireNonNull(tableName, "表名为空");

        // 判断condition中列是否都在此table中
        GenTable gent = cmdService.getTableFromRedisByTableName(RedisKey.TABLE_INFO, tableName);
        List<GenTableColumn> columns = gent.getColumns();
        ColumnUtils.checkColumn(param, columns);
        JSONObject packColCondition = ColumnUtils.packColCondition(columns, param);
        List<JSONObject> result = mapper.getByMap(tableName, packColCondition, param, true);

        List<String> showData = filterData(columns, 4, null, MaskConstant.LIST_VISIBLE::equals);
        // 查询时为null的列不显示的处理
        handleNullColumnValue(result, showData);
        handleBlob(result, gent.getIsContainsBlob());
        handleDateTimeForQueryList(result, gent.getColumns());
        handleDictForQueryList(result, gent.getColumns());
        handleFkForQueryList(result, gent.getColumns());

        return isEmpty(result) ? null : result.get(0);
    }

    /**
     * 功能描述: 根据条件查询
     *
     * @param tableName     tableName
     * @param packCondition 封装的查询条件
     * @return int
     */
    @Override
    public int countByCondition(String tableName, JSONObject packCondition, JSONObject condition) {
        requireNonNull(tableName, "表名为空");

        return mapper.countByCondition(tableName, packCondition, condition);
    }

    /**
     * 功能描述: 根据条件查询
     *
     * @param queryBySql    dto
     * @param packCondition packCondition
     * @return int
     */
    @Override
    public int countByLeftJoinCondition(JSONObject packCondition, QueryBySqlDto queryBySql, JSONObject condition) {
        return mapper.countByLeftJoinCondition(packCondition, queryBySql, condition);
    }

    /**
     * 功能描述: 根据id查所有，不支持自定义查询列
     *
     * @param tableName 表名
     * @param pkName    主键名称
     * @param id        主键值
     * @return com.alibaba.fastjson.JSONObject
     */
    @Override
    public JSONObject selectById(String tableName, String pkName, Long id, String other) {
        requireNonNull(tableName, "表名为空");
        requireNonNull(pkName, "主键名称为空");;
        requireNonNull(id, "selectById id is empty");
        return mapper.selectById(tableName, pkName, id, other);
    }

    /**
     * 功能描述: 根据id查所有，不支持自定义查询列
     *
     * @param tableName 表名
     * @param pkName    主键名称
     * @param idList    主键值
     * @param showData  需要展示的列
     * @return com.alibaba.fastjson.JSONObject
     */
    @Override
    public List<JSONObject> selectByIdList(String tableName, String pkName, List<Long> idList, List<String> showData) {
        requireNonNull(tableName, "表名为空");
        requireNonNull(pkName, "主键名称为空");;
        requireNonNull(idList, "selectByIdList idList is empty");

        return mapper.selectByIdList(tableName, pkName, idList, showData);
    }

    /**
     * 功能描述: 获取最新的一条数据 create desc
     *
     * @param tableName tableName
     * @return jcom.alibaba.fastjson.JSONObject
     */
    @Override
    public JSONObject getNewest(String tableName) {
        requireNonNull(tableName, "tableName is empty");
        return mapper.getNewest(tableName);
    }
}
