package cn.com.capcloud.api.action;

import cn.com.capcloud.api.action.service.*;
import cn.com.capcloud.api.action.service.util.QueryConditionUtil;
import cn.com.capcloud.api.action.service.util.ReflectionUtil;
import cn.com.capcloud.api.action.service.util.TextUtil;
import cn.com.capcloud.ccui.core.common.json.JackJSON;
import cn.com.capcloud.ccui.core.common.json.JackJSONObject;
import cn.com.capcloud.ccui.core.common.utils.StringUtil;
import cn.com.capcloud.core.cache.BaseConfigStaticCache;
import cn.com.capcloud.core.lucene.LuceneIndexManager;
import cn.com.capcloud.core.lucene.SearchParam;
import cn.com.capcloud.core.noentitydb.BaseService;
import cn.com.capcloud.core.noentitydb.DefaultActionFace;
import cn.com.capcloud.core.noentitydb.JtPage;
import cn.com.capcloud.core.system.user.User;
import cn.com.capcloud.core.system.user.UserService;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;

import org.springframework.beans.factory.annotation.Autowired;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Component
public class ApiQueryAction {

    private static final org.slf4j.Logger logger = LoggerFactory.getLogger(ApiQueryAction.class);
    //自动填充用户信息(KEY)
    private static final String SYSTEM_SETTINGS_DS_FORM_AUTO_USER="system.settings.ds.form.auto.user.json";
    @Autowired
    private BaseService baseService;
    @Autowired
    private JdbcTemplate jdbcTemplate;
    @Autowired
    private ApiService apiService;
    @Autowired
    private DictService dictService;
    @Autowired
    private UserService userService;
    @Autowired
    private DataSourceService dsService;
    @Autowired
    private LuceneIndexManager luceneIndexManager;
    @Autowired
    private ShowValueService svService;
    @Autowired
    private ActionResolveService actionResolveService;

    private String successResponse(Object data) {
        JackJSONObject retJson = JackJSONObject.fromObject(apiService.getReturnDataByCode("ok"));
        retJson.put("data", data);
        return JackJSON.toJSONString(retJson);
    }

    private String failResponse(JackJSONObject retJson) {
        return JackJSON.toJSONString(retJson);
    }

    public String page(String jsonStr, HttpServletRequest request){
        JackJSONObject retJson=new JackJSONObject();
        JackJSONObject dataJson=new JackJSONObject();
        String pageCode=apiService.getJsonValueByKey(jsonStr,retJson,"pageCode");
        if("-1".equals(pageCode)){
            return failResponse(retJson);
        }
        Map<String, Object> returnMap = apiService.getPageInfo(jsonStr,retJson,request);
        if(returnMap.size()==0){
            return failResponse(retJson);
        }
        return successResponse(returnMap);
    }
    public String list(String jsonStr, HttpServletRequest request){
        JackJSONObject retJson=new JackJSONObject();
        JackJSONObject dataJson=new JackJSONObject();
        String uuid=dsService.getDataSourceUuid(jsonStr,retJson,dataJson);
        if ("-1".equals(uuid)) {
            return failResponse(retJson);
        }
        dsService.getDataSourceInfo(jsonStr,uuid,retJson,dataJson);
        if("-1".equals(dsService.getFormInfo(jsonStr,uuid,retJson,dataJson,request))){
            return failResponse(retJson);
        }else{
            if(StringUtil.isNotEmpty(dataJson.get("form"))){
                User user=userService.getUser(request);
                String sql="SELECT "+ BaseConfigStaticCache.get(SYSTEM_SETTINGS_DS_FORM_AUTO_USER) +" FROM tbl_system_user WHERE id="+user.getId();
                List<Map<String,Object>> userList=jdbcTemplate.queryForList(sql);
                dataJson.getJackJSONObject("form").put("user",userList.get(0));
            }
        }
        if("-1".equals(dsService.getQueryInfo(jsonStr,uuid,retJson,dataJson,request))){
            return failResponse(retJson);
        }
        return successResponse(dataJson);
    }
    public String showAll(String jsonStr, HttpServletRequest request){
        JackJSONObject retJson=new JackJSONObject();
        JackJSONObject dataJson=new JackJSONObject();
        Map<String,Object> dsMap=dsService.findDataSourceByJsonStr(jsonStr,retJson,dataJson);
        if (dsMap==null) {
            return failResponse(retJson);
        }
        Map<String, Object> queryMap=dsService.resolveQuery(jsonStr,retJson,retJson);
        if(queryMap==null){
            return failResponse(retJson);
        }
        ActionResolveService.ActionResolveResult actionResolveResult =
                actionResolveService.resolveAction(dsMap, retJson);
        if (actionResolveResult == null) {
            return failResponse(retJson);
        }
        DefaultActionFace actionImpl = actionResolveResult.getActionImpl();
        Boolean existsAction = actionResolveResult.isExistsAction();
        String actionClass = actionResolveResult.getActionClass();
        String sql;
        String buildSql=String.valueOf(queryMap.get("build_sql"));
        if(existsAction&&StringUtil.isNotEmpty(buildSql)){
            sql = ReflectionUtil.mySelfMethodRetStr(actionClass,buildSql,jsonStr,retJson,request);
        }else{
            sql = actionImpl.buildSql(jsonStr,retJson,request);
        }
        if("-1".equals(sql)){
            return failResponse(retJson);
        }
        String powerSql;
        String buildPowerSql=String.valueOf(queryMap.get("build_power_sql"));
        if(existsAction&&StringUtil.isNotEmpty(buildPowerSql)){
            powerSql = ReflectionUtil.mySelfMethodRetStr(actionClass,buildPowerSql,jsonStr,retJson,request);
        }else{
            powerSql = actionImpl.buildPowerSql(jsonStr,retJson,request);
        }
        if("-1".equals(powerSql)){
            return failResponse(retJson);
        }
        sql=sql+powerSql;
        String sqlCount;
        String buildSqlCount=String.valueOf(queryMap.get("build_sql_count"));
        if(existsAction&&StringUtil.isNotEmpty(buildSqlCount)){
            sqlCount = ReflectionUtil.mySelfMethodRetStr(actionClass,buildSqlCount,jsonStr,retJson,request);
        }else{
            sqlCount = sql;//改成如下，如果count影响效率可重写buildSqlCount，在该方法优化sql即可。
        }
        if("-1".equals(sqlCount)){
            return failResponse(retJson);
        }
        actionImpl.buildSqlCount(jsonStr,retJson,request);
        String orderBy=dsService.getOrderBySql(jsonStr,retJson);
        if ("-1".equals(orderBy)) {
            return failResponse(retJson);
        }
        Map<String,Object> pageMap=new HashMap<>();
        dsService.getLimitPage(jsonStr,pageMap);
        logger.debug(sql+orderBy);
        Integer page=Integer.valueOf(String.valueOf(pageMap.get("page")));
        Integer pageSize=Integer.valueOf(String.valueOf(pageMap.get("pageSize")));
        //查询选中的内容
        JackJSONObject jsonObject = JackJSONObject.fromObject(jsonStr).getJackJSONObject("queryParam");
        String isLucene=String.valueOf(dsMap.get("is_lucene"));
        JtPage jtPage=null;
        if(isLucene.equals("Y")){
            String tableName=String.valueOf(dsMap.get("ds_table_name"));
            String dsUUID=String.valueOf(dsMap.get("uuid"));
            List<Map<String,Object>> fieldList=dsService.getQueryInfo(jsonStr);
            List<SearchParam> listSear= QueryConditionUtil.getLuceneSearchParam(tableName,fieldList, jsonStr,jdbcTemplate,retJson);
            if(listSear.size()>0){
                try {
                    jtPage=luceneIndexManager.searchMultipleQuery(listSear,(page+1),pageSize,tableName,dsUUID);
                    jtPage.setNumber(jtPage.getNumber()-1);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }else{
                jtPage=baseService.query(sql+orderBy,page,pageSize,sqlCount);
            }
        }else{
            jtPage=baseService.query(sql+orderBy,page,pageSize,sqlCount);
        }

        jtPage = actionImpl.showAllDesensitize(jsonStr,retJson,request,jtPage);
        if(jtPage==null){
            return failResponse(retJson);
        }
        String selectTableDataArray = String.valueOf(jsonObject.get("selectTableDataArray"));
        if(!selectTableDataArray.equals("null")&&selectTableDataArray.length()>0){
            String tableName=String.valueOf(dsMap.get("ds_table_name"));
            String selectDataSql="select * from "+tableName +" where id in("+selectTableDataArray+") "+orderBy;
            List<Map<String, Object>> selectContent=jdbcTemplate.queryForList(selectDataSql);
            jtPage.setSelectContent(selectContent);
        }
        svService.valueRewrite(jsonStr,request,jtPage);
        String showAllAfter=String.valueOf(queryMap.get("show_all_after"));
        if(existsAction&&StringUtil.isNotEmpty(showAllAfter)){
            jtPage = ReflectionUtil.mySelfMethodRetJtPage(actionClass,showAllAfter,jsonStr,retJson,request,jtPage);
        }else{
            jtPage = actionImpl.showAllAfter(jsonStr,retJson,request,jtPage);
        }
        if(jtPage==null){
            return failResponse(retJson);
        }
        return successResponse(jtPage);
    }

    public String findOne(String jsonStr, HttpServletRequest request){
        JackJSONObject retJson=new JackJSONObject();
        JackJSONObject dataJson=new JackJSONObject();
        Map<String,Object> dsMap=dsService.findDataSourceByJsonStr(jsonStr,retJson,dataJson);
        if (dsMap==null) {
            return failResponse(retJson);
        }
        Map<String, Object> queryMap=dsService.resolveQuery(jsonStr,retJson,retJson);
        if(queryMap==null){
            return failResponse(retJson);
        }
        ActionResolveService.ActionResolveResult actionResolveResult =
                actionResolveService.resolveAction(dsMap, retJson);
        if (actionResolveResult == null) {
            return failResponse(retJson);
        }
        DefaultActionFace actionImpl = actionResolveResult.getActionImpl();
        Boolean existsAction = actionResolveResult.isExistsAction();
        String actionClass = actionResolveResult.getActionClass();
        /**
         * 如果不是使用默认的主键当查询条件，请注意前端传过来的查询条件要唯一的。
         */
        String pkFieldId=String.valueOf(JackJSONObject.fromObject(jsonStr).get("pkFieldId"));
        if(StringUtil.isEmpty(pkFieldId)){
            pkFieldId=String.valueOf(dsMap.get("ds_pk_id"));
        }
        Map<String,Object> returnMap = new HashMap<>();
        String isLucene=String.valueOf(dsMap.get("is_lucene"));
        if(isLucene.equals("Y")){
            String pkId=String.valueOf(JackJSONObject.fromObject(jsonStr).get("pkId"));
            String tableName=String.valueOf(dsMap.get("ds_table_name"));
            returnMap = baseService.findOne(tableName, pkId,pkFieldId);
        }else{
            String sql;
            String buildSql=String.valueOf(queryMap.get("build_sql"));
            if(existsAction&&StringUtil.isNotEmpty(buildSql)){
                sql = ReflectionUtil.mySelfMethodRetStr(actionClass,buildSql,jsonStr,retJson,request);
            }else{
                sql = actionImpl.buildSql(jsonStr,retJson,request);
            }
            if("-1".equals(sql)){
                return failResponse(retJson);
            }
            String powerSql;
            String buildPowerSql=String.valueOf(queryMap.get("build_power_sql"));
            if(existsAction&&StringUtil.isNotEmpty(buildPowerSql)){
                powerSql = ReflectionUtil.mySelfMethodRetStr(actionClass,buildPowerSql,jsonStr,retJson,request);
            }else{
                powerSql = actionImpl.buildPowerSql(jsonStr,retJson,request);
            }
            if("-1".equals(powerSql)){
                return failResponse(retJson);
            }
            String pkId=String.valueOf(JackJSONObject.fromObject(jsonStr).get("pkId"));
            sql=sql+powerSql+" and "+pkFieldId+"='"+pkId+"'";//todo 这块先默认都是字符串，且在MySQL是加单引号是不影响的，如果更换数据库影响请动态判断
            System.out.println(sql);
            try {
                returnMap = jdbcTemplate.queryForMap(sql);
            } catch (Exception e) {
                if(!pkFieldId.equals("page_parent_uuid")){
                    retJson.putAll(JackJSONObject.fromObject(apiService.getReturnDataByCode("4031")));
                    return failResponse(retJson);
                }else{
                    returnMap=new HashMap<>();
                }
            }
        }
        /*
         * retSaveMap.put("process_instance_id", String.valueOf(processInfo.getProcessInstanceId()));//流程实例ID
            	retSaveMap.put("process_definition_id", String.valueOf(processInfo.getProcessDefinitionId()));//流程图ID

            	Task task=processService.getFirstTask(processInfo.getProcessInstanceId());
            	retSaveMap.put("process_task_id", String.valueOf(task.getId()));
         */
        //如果有工作流字段，且工作流字段有值，则获取下一节点信息，并取出按钮

        returnMap=JackJSON.parseObject(TextUtil.nullToStrFilter(returnMap), HashMap.class);
        if(returnMap.size()>0){
            String findOneAfter=String.valueOf(queryMap.get("find_one_after"));
            if(existsAction&&StringUtil.isNotEmpty(findOneAfter)){
                returnMap = ReflectionUtil.mySelfMethodRetMap(actionClass,findOneAfter,jsonStr,retJson,request,returnMap);
            }else{
                returnMap = actionImpl.findOneAfter(jsonStr,retJson,request,returnMap);
            }
            if(returnMap.size()==0){
                return failResponse(retJson);
            }
            String valueToShowValue=String.valueOf(JackJSONObject.fromObject(jsonStr).get("valueToShowValue"));
            if(valueToShowValue.equals("Y")){//字典转换
                svService.valueToShowValue(jsonStr,request,returnMap);
            }
        }

        return successResponse(returnMap);
    }

    public String showAllForTree(String jsonStr, HttpServletRequest request){
        JackJSONObject retJson=new JackJSONObject();
        JackJSONObject dataJson=new JackJSONObject();
        String treeCode=apiService.getJsonValueByKey(jsonStr,retJson,"treeCode");
        if("-1".equals(treeCode)){
            return failResponse(retJson);
        }
        Map<String, Object> returnMap = dictService.getAllTree(jsonStr,retJson,request);
        if(returnMap.size()==0){
            return failResponse(retJson);
        }
        return successResponse(returnMap);
    }

    public String showAllForOutDict(String jsonStr, HttpServletRequest request){
        JackJSONObject retJson=new JackJSONObject();
        JackJSONObject dataJson=new JackJSONObject();
        String oDictCode=apiService.getJsonValueByKey(jsonStr,retJson,"oDictCode");
        if("-1".equals(oDictCode)){
            return failResponse(retJson);
        }
        Map<String, Object> returnMap = dictService.getAllOutDict(jsonStr,retJson,request);
        if(returnMap.size()==0){
            return failResponse(retJson);
        }
        return successResponse(returnMap);
    }

    public String myAction(String jsonStr, HttpServletRequest request){
        JackJSONObject retJson=new JackJSONObject();
        JackJSONObject dataJson=new JackJSONObject();
        String uuid=dsService.getDataSourceUuid(jsonStr,retJson,dataJson);
        if ("-1".equals(uuid)) {
            return failResponse(retJson);
        }
        Map<String,Object> returnMap=apiService.executeMyActionMethod(jsonStr,retJson,request);
        if(returnMap.size()==0){
            return failResponse(retJson);
        }
        return successResponse(JackJSONObject.fromObject(returnMap));
    }

    public String login(String jsonStr, HttpServletRequest request){
        JackJSONObject retJson=new JackJSONObject();
        JackJSONObject dataJson=new JackJSONObject();
        String uuid=dsService.getDataSourceUuid(jsonStr,retJson,dataJson);
        if ("-1".equals(uuid)) {
            return failResponse(retJson);
        }
        JackJSONObject jsonObject=JackJSONObject.fromObject(jsonStr);
        jsonObject.put("methodName","login");//固定login方法
        jsonStr =JackJSON.toJSONString(jsonObject);
        Map<String,Object> returnMap=apiService.executeMyActionMethod(jsonStr,retJson,request);
        if(returnMap.size()==0){
            return failResponse(retJson);
        }
        return successResponse(returnMap);
    }

}

