package cn.com.capcloud.api.action;

import cn.com.capcloud.api.action.service.*;
import cn.com.capcloud.api.action.service.util.ReflectionUtil;
import cn.com.capcloud.ccui.core.common.json.JackJSON;
import cn.com.capcloud.ccui.core.common.json.JackJSONArray;
import cn.com.capcloud.ccui.core.common.json.JackJSONObject;
import cn.com.capcloud.ccui.core.common.utils.StringUtil;
import cn.com.capcloud.ccui.core.common.utils.UUIDUtils;
import cn.com.capcloud.core.lucene.LuceneIndexManager;
import cn.com.capcloud.core.noentitydb.BaseService;
import cn.com.capcloud.core.noentitydb.DefaultActionFace;
import cn.com.capcloud.core.system.user.User;
import cn.com.capcloud.core.system.user.UserService;
import org.joda.time.DateTime;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;

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

@Component
public class ApiCrudAction {

    private static final org.slf4j.Logger logger = LoggerFactory.getLogger(ApiCrudAction.class);
    @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 LogService logService;
    @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);
    }

    @Transactional
    public String save(String jsonStr, HttpServletRequest request){

    	User user=userService.getUser(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> formMap=dsService.resolveForm(jsonStr,retJson,retJson);
        if(formMap==null){
            return failResponse(retJson);
        }
        String isTree=String.valueOf(formMap.get("is_tree"));
        String saveBefore=String.valueOf(formMap.get("save_before"));
        String saveAfter=String.valueOf(formMap.get("save_after"));
        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();
        JackJSONArray saveData=JackJSONObject.fromObject(jsonStr).getJackJSONArray("saveData");
        String tableName=String.valueOf(dsMap.get("ds_table_name"));
        if(isTree.equals("Y")){//是否tree表
            String idField=String.valueOf(formMap.get("t_id"));
            String pIdField=String.valueOf(formMap.get("t_p_id"));
            String levelField=String.valueOf(formMap.get("t_level"));
            for (int i = 0; i < saveData.size(); i++) {
                String id=String.valueOf(saveData.getJackJSONObject(i).get(idField));
                Integer level=0;
                String levelStr=String.valueOf(saveData.getJackJSONObject(i).get(levelField));
                String pId=String.valueOf(saveData.getJackJSONObject(i).get(pIdField));
                String querySql="select "+levelField+" from "+tableName +" where "+idField+"='"+pId+"'";
                try {
                    level=jdbcTemplate.queryForObject(querySql,Integer.class);
                    level=level+1;//因为查询出的是上级部门层级，需加1
                } catch (DataAccessException e) {
                    level=1;//查不到默认一级
                }
                saveData.getJackJSONObject(i).put(levelField,level);
                if(StringUtil.isNotEmpty(id)){//刷新下级的level
                    Map<String,Object> map=new HashMap<>();
                    map.put(pIdField,id);
                    map.put("pIdField",pIdField);
                    map.put(levelField,level+1);
                    map.put("levelField",levelField);
                    map.put("idField",idField);
                    map.put("tableName",tableName);
                    dictService.refreshChildLevel(map);
                }
            }
        }
        DateTime d = new DateTime();
        if(existsAction&&StringUtil.isNotEmpty(saveBefore)){
            saveData = ReflectionUtil.mySelfMethodRetListMap(actionClass,saveBefore,jsonStr,retJson,request,saveData);
        }else{
            saveData = actionImpl.saveBefore(jsonStr,retJson,request,saveData);
        }
        if(saveData.size()==0){
            return failResponse(retJson);
        }
        String pkFieldName = String.valueOf(dsMap.get("ds_pk_id"));
        String pkId=String.valueOf(saveData.getJackJSONObject(0).get(pkFieldName));
        //保存之前后端也验证数据（验证一些值是否唯一）
        String validate=dsService.saveBeforeValidate(jsonStr,saveData,retJson,request);
        if ("-1".equals(validate)) {
            return failResponse(retJson);
        }
        //新增数据
        if(StringUtil.isEmpty(pkId)){
            for (int i = 0; i < saveData.size(); i++) {
                String uuid=String.valueOf(saveData.getJackJSONObject(i).get("uuid"));
                if(StringUtil.isEmpty(uuid)){
                    uuid= UUIDUtils.randomUuidWithoutHyphen();
                    saveData.getJackJSONObject(i).put("uuid", uuid);
                }
                saveData.getJackJSONObject(i).remove(dsMap.get("ds_pk_id"));
                saveData.getJackJSONObject(i).put("status",0);
                saveData.getJackJSONObject(i).put("data_source","form");
                saveData.getJackJSONObject(i).put("form_version",formMap.get("form_version"));
            }
            Map<String, Object> retSaveMap=null;
            for (int i = 0; i < saveData.size(); i++) {//todo 虽然有批量保存实现，但不建议在前端使用批量插入，可以批量修改
                if(i==0){
                    retSaveMap=baseService.save(tableName,saveData.getJackJSONObject(i),user);
                }else{
                    baseService.save(tableName,saveData.getJackJSONObject(i),user);
                }
                logService.cudLogSave("create",retSaveMap.get(pkFieldName)+"",dsMap,request,saveData,new JackJSONArray());
            }
            saveData.set(0,retSaveMap);//将旧的值覆盖一下
        }else{//update数据
            String ids="";
            for (int i = 0; i < saveData.size(); i++) {
                saveData.getJackJSONObject(i).put("update_user",user.getUserName());
                saveData.getJackJSONObject(i).put("update_time",d.toString("yyyy-MM-dd HH:mm:ss"));
                saveData.getJackJSONObject(i).put("update_date",d.toString("yyyy-MM-dd"));
                ids+=saveData.getJackJSONObject(i).get(pkFieldName)+",";
            }
            ids=ids.substring(0,ids.length()-1);
            String queryCode=apiService.getJsonValueByKey(jsonStr,retJson,"queryCode");
            if(!"-1".equals(queryCode)){
                Map<String, Object> queryMap=dsService.resolveQuery(jsonStr,retJson,dataJson);
                if(queryMap.size()>0){
                    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+" and "+pkFieldName+" in("+ids+")";//todo 这块先默认都是字符串，且在MySQL是加单引号是不影响的，如果更换数据库影响请动态判断
                    System.out.println(sql);
                    //Map<String,Object> returnMap = action.baseService.findOne(tableName, pkId,pkFieldId);
                    List<Map<String,Object>> returnList = jdbcTemplate.queryForList(sql);
                    if(returnList.size()!=saveData.size()){
                        retJson.putAll(JackJSONObject.fromObject(apiService.getReturnDataByCode("4031")));
                        return failResponse(retJson);
                    }
                }
            }
            JackJSONArray oldSaveData=new JackJSONArray();
            if(saveData.size()==1){
                String sql="select * from "+tableName+" where "+pkFieldName+"='"+saveData.getJackJSONObject(0).get(pkFieldName)+"'";
                oldSaveData= JackJSONArray.fromObject(jdbcTemplate.queryForList(sql));
                String enableHistory = String.valueOf(dsMap.get("enable_history"));
                if(enableHistory.equals("Y")){
                    JackJSONObject historyJson=oldSaveData.getJackJSONObject(0);
                    String historyUUID=String.valueOf(historyJson.get("uuid"));
                    historyJson.put("is_history","Y");
                    historyJson.put("status","2"); // 0有效，1删除，2历史
                    historyJson.put("page_parent_uuid", historyUUID);
                    historyJson.remove("id");
                    historyJson.remove("uuid");
                    baseService.save(tableName, historyJson);
                }
            }
            baseService.update(tableName, (List) saveData);
            logService.cudLogSave("update",ids,dsMap,request,saveData,oldSaveData);
        }
        String isLucene=String.valueOf(dsMap.get("is_lucene"));
        if(isLucene.equals("Y")){//更新全文索引
            for (int i = 0; i < saveData.size(); i++) {
                String dsUUID=String.valueOf(dsMap.get("uuid"));
                String dataUUID=String.valueOf(saveData.getJackJSONObject(i).get("uuid"));
                luceneIndexManager.updateIndex(tableName,dsUUID,dataUUID);//对单条数据索引更新
            }
        }
        String enableJob=String.valueOf(dsMap.get("enable_job"));
        String jobClassPath=String.valueOf(dsMap.get("job_class_path"));
        if(enableJob.equals("Y")&&!jobClassPath.equals("null")&&jobClassPath.length()>0){
            JackJSONObject rowData=saveData.getJackJSONObject(0);
            String cronExpression=String.valueOf(rowData.get("cron_expression"));
            if(!cronExpression.equals("null")&&cronExpression.length()>0){
                apiService.executeJobByMethodName(jobClassPath,dsMap,rowData,"start");
            }else{
                apiService.executeJobByMethodName(jobClassPath,dsMap,rowData,"stop");
            }
        }
        if(existsAction&&StringUtil.isNotEmpty(saveAfter)){
            saveData = ReflectionUtil.mySelfMethodRetListMap(actionClass,saveAfter,jsonStr,retJson,request,saveData);
        }else{
            saveData = actionImpl.saveAfter(jsonStr,retJson,request,saveData);
        }
        if(saveData.size()==0){
            return failResponse(retJson);
        }
        dataJson.put("saveData",saveData);
        return successResponse(dataJson);
    }

    public String insertOne(String jsonStr, HttpServletRequest request){
        JackJSONObject retJson=new JackJSONObject();
        JackJSONObject dataJson=new JackJSONObject();
        User user=userService.getUser(request);
        Map<String,Object> dsMap=dsService.findDataSourceByJsonStr(jsonStr,retJson,dataJson);
        if (dsMap==null) {
            return failResponse(retJson);
        }
        Map<String, Object> formMap=dsService.resolveForm(jsonStr,retJson,retJson);
        if(formMap==null){
            return failResponse(retJson);
        }
        JackJSONArray saveData=JackJSONObject.fromObject(jsonStr).getJackJSONArray("saveData");
        saveData.getJackJSONObject(0).put("data_source","form");
        saveData.getJackJSONObject(0).put("form_version",formMap.get("form_version"));
        baseService.save(String.valueOf(dsMap.get("ds_table_name")), (List) saveData,user);
        return successResponse("");
    }

    public String del(String jsonStr, HttpServletRequest request){
        //注：formCode为必须参数，因为在form组件里需要用到一些配置
        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> dsMap=dsService.findDataSourceByUuid(uuid);
        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();
        JackJSONArray pkIds=JackJSONObject.fromObject(jsonStr).getJackJSONArray("pkIds");
        String tableName=String.valueOf(dsMap.get("ds_table_name"));
        Map<String, Object> formMap=dsService.resolveForm(jsonStr,retJson,retJson);
        if(formMap==null){
            return failResponse(retJson);
        }
        String isTree=String.valueOf(formMap.get("is_tree"));
        String pIdField=String.valueOf(formMap.get("t_p_id"));
        String pkFieldName = String.valueOf(dsMap.get("ds_pk_id"));
        if(isTree.equals("Y")){
            for (int i = 0; i < pkIds.size(); i++) {
                String queryCountSql="SELECT count(1) FROM "+tableName+" WHERE STATUS=0 AND "+pIdField+"='"+pkIds.getJackJSONObject(i).get("pkId")+"'";
                Integer count=jdbcTemplate.queryForObject(queryCountSql,Integer.class);
                if(count>0){
                    retJson.putAll(JackJSONObject.fromObject(apiService.getReturnDataByCode("7011")));
                    retJson.put("message",retJson.get("message")+" 原因是当前有子数据");
                    return failResponse(retJson);
                }
            }
        }
        String deleteBefore=String.valueOf(queryMap.get("delete_before"));
        String beforeRet;
        if(existsAction&&StringUtil.isNotEmpty(deleteBefore)){
            beforeRet= ReflectionUtil.mySelfMethodRetStr(actionClass,deleteBefore,jsonStr,retJson,request);
        }else{
            beforeRet=actionImpl.deleteBefore(jsonStr,retJson,request);
        }
        if("-1".equals(beforeRet)){//自定义的方法需要返回一个字符串，返回null则抛错误信息
            return failResponse(retJson);
        }
        String buildDeleteSql=String.valueOf(queryMap.get("build_delete_sql"));
        String deleteSql;
        if(existsAction&&StringUtil.isNotEmpty(buildDeleteSql)){
            deleteSql= ReflectionUtil.mySelfMethodRetStr(actionClass,buildDeleteSql,jsonStr,retJson,request);
        }else{
            deleteSql=actionImpl.buildDeleteSql(jsonStr,retJson,request);
        }
        if("-1".equals(deleteSql)){
            return failResponse(retJson);
        }
        jdbcTemplate.execute(deleteSql);
        String ids="";
        for (int i = 0; i < pkIds.size(); i++) {
            ids+=pkIds.getJackJSONObject(i).get("pkId")+",";
        }
        JackJSONArray oldDeleteData=new JackJSONArray();
        if(pkIds.size()==1){
            String sql="select * from "+dsMap.get("ds_table_name")+" where "+pkFieldName+"='"+pkIds.getJackJSONObject(0).get("pkId")+"'";
            oldDeleteData= JackJSONArray.fromObject(jdbcTemplate.queryForList(sql));
        }
        logService.cudLogSave("delete",ids.substring(0,ids.length()-1),dsMap,request,new JackJSONArray(),oldDeleteData);
        String isLucene=String.valueOf(dsMap.get("is_lucene"));
        if(isLucene.equals("Y")){//对单条数据索引删除
            for (int i = 0; i < oldDeleteData.size(); i++) {
                String dataUUID=String.valueOf(oldDeleteData.getJackJSONObject(i).get("uuid"));
                try {//对单条数据索引删除
                    luceneIndexManager.deleteIndexByUuid(tableName,dataUUID);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        String deleteAfter=String.valueOf(queryMap.get("delete_after"));
        String afterRet;
        if(existsAction&&StringUtil.isNotEmpty(deleteAfter)){
            afterRet= ReflectionUtil.mySelfMethodRetStr(actionClass,deleteAfter,jsonStr,retJson,request);
        }else{
            afterRet=actionImpl.deleteAfter(jsonStr,retJson,request);
        }
        if("-1".equals(afterRet)){
            return failResponse(retJson);
        }
        return successResponse("");
    }

}

