package com.seeyon.apps.src_ydctdatasync.quartz;

import cn.hutool.log.Log;
import com.seeyon.apps.common.config.ICstConfigApi;
import com.seeyon.apps.common.plugin.vo.ConfigVo;
import com.seeyon.apps.ext.quartz.AbstractQuartzTask;
import com.seeyon.apps.src_ydctdatasync.constants.YdzbdataSyncConstants;
import com.seeyon.apps.src_ydctdatasync.dao.FormExportUtil;
import com.seeyon.apps.src_ydctdatasync.datamap.BzfAssetMode;
import com.seeyon.apps.src_ydctdatasync.datamap.ContractBillMode;
import com.seeyon.apps.src_ydctdatasync.datamap.ContractMode;
import com.seeyon.apps.src_ydctdatasync.datamap.GzcfAssetMode;
import com.seeyon.apps.src_ydctdatasync.datamap.GzfwAssetMode;
import com.seeyon.apps.src_ydctdatasync.datamap.GztdAssetMode;
import com.seeyon.apps.src_ydctdatasync.datamap.HydropowerRechargeDataMapMode;
import com.seeyon.apps.src_ydctdatasync.datamap.RefundDataMapMode;
import com.seeyon.apps.src_ydctdatasync.datasource.DataSource;
import com.seeyon.apps.src_ydctdatasync.utils.StatementQueryUtil;
import com.seeyon.apps.src_ydctdatasync.utils.TimeUtils;
import com.seeyon.ctp.common.AppContext;
import com.seeyon.ctp.common.exceptions.BusinessException;
import com.seeyon.ctp.services.ServiceException;
import com.seeyon.ctp.util.JDBCAgent;
import com.seeyon.v3x.services.form.FormFactory;
import com.seeyon.v3x.services.form.bean.FormExport;
import org.springframework.beans.factory.DisposableBean;

import java.sql.Connection;
import java.sql.SQLException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static com.seeyon.apps.src_ydctdatasync.constants.YdzbdataSyncConstants.getPluginId;

public class YdzbDataSyncQuartz extends AbstractQuartzTask implements DisposableBean {

	private static Log log = Log.get(YdzbDataSyncQuartz.class);
	protected ICstConfigApi cstConfigApi = (ICstConfigApi) AppContext.getBean("cstConfigApi");
	private FormFactory formFactory;
	private DataSource ydzbThirdDataSource = (DataSource) AppContext.getBean("ydzbThirdDataSource");
	private JDBCAgent agent = null;
	private boolean prod;

	public boolean isProd() {
		return prod;
	}

	public void setProd(boolean prod) {
		this.prod = prod;
	}

	public FormFactory getFormFactory() {
		if (formFactory == null) {
			formFactory = (FormFactory) AppContext.getBean("formFactory");
		}
		return formFactory;
	}

	public void setFormFactory(FormFactory formFactory) {
		this.formFactory = formFactory;
	}

	@Override
	public String getName() {
		return "宜都城投资产数据同步任务";
	}

	@Override
	public String taskRun(String arg0) {
		log.info("宜都城投资产数据同步任务任务开始");
		long startTime = System.currentTimeMillis();
		try (Connection connection = ydzbThirdDataSource.getConnection()){
			agent = new JDBCAgent();
			processZcData(connection);
			processContractData(connection);
			DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
			if (!"-1".equals(arg0)) {
				try {
					Date date = null;
					if(arg0 != null) {
						date = df.parse(arg0);
					}
					processFeeData(connection, date);
				}catch (ParseException e) {
					throw e;
				}
			}
		} catch (Exception e) {
			log.error("宜都城投资产数据同步任务执行失败");
			log.error(e.getMessage(),e);
		}finally {
			if(agent != null) {
				agent.close();
			}
		}
		log.info("宜都城投资产数据同步任务任务结束,耗时:"+ (System.currentTimeMillis() - startTime)+ " ms");
		return null;
	}

	//处理合同数据
	private void processContractData(Connection connection) throws SQLException, BusinessException, ServiceException {
		log.info("开始同步合同表数据");
		String countQuerySql = "SELECT count(*) FROM zb_contract;";
		String pageQuerySql = "SELECT * FROM zzb_contract limit 100 OFFSET ?;";
		ContractMode contractMode = new ContractMode();
		contractMode.setAgent(agent);
		contractMode.setZcRootPcode(getBizConfigByKey(YdzbdataSyncConstants.zcRootEnumPCode));
		long count = StatementQueryUtil.queryCount(countQuerySql,connection, null);
		int totalPage = (int)Math.ceil((double)count / 100);
		for(int i = 0; i < totalPage;i++) {
			List<Map<String, Object>> contractDataList = StatementQueryUtil.queryList(pageQuerySql, connection, i*100);
			for (Map<String, Object> rowMap : contractDataList) {
				Map<String, Object> targetMap = new HashMap<>();
				contractMode.preProcess(rowMap);
				contractMode.transfer(targetMap,rowMap);
				Map<String,Object> subMap = (Map<String,Object>)targetMap.get("subTable");
				targetMap.remove("subTable");
				upsertData(getBizConfigByKey(YdzbdataSyncConstants.contractFormNo),
						convert2StringValue(targetMap),
						getBizConfigByKey(YdzbdataSyncConstants.contractTable),
						convert2StringValue(subMap),
						"WHERE field0003 = ?", (String) targetMap.get("合同编号"));
			}
		}
		log.info("合同表数据同步结束");
	}

	//处理费用数据
	private void processFeeData(Connection connection,Date date) throws SQLException, BusinessException, ServiceException {
		Date startDate = null;
		Date endDate = null;
		if(date == null) {
			startDate = TimeUtils.startOfYesterday();
			endDate = TimeUtils.startOf(new Date());
		}else {
			startDate = TimeUtils.startOf(TimeUtils.before(date,1));
			endDate = TimeUtils.startOf(date);
		}
		log.info("开始同步费用数据");
		processContractBillData(connection,startDate,endDate);
		processRefundData(connection,startDate,endDate);
		processHydpowerRechargeData(connection,startDate,endDate);
		log.info("费用数据同步结束");
	}

	//处理合同费用
	private void processContractBillData(Connection connection,Date startDate,Date endDate) throws SQLException, BusinessException, ServiceException {
		log.info("开始同步合同费用数据");
		String countQuerySql = "SELECT count(*) FROM zb_contract_bill where trade_reconciliation_time >= ? and trade_reconciliation_time <= ?;";
		String pageQuerySql = "SELECT * FROM zb_contract_bill where limit 100 OFFSET ?;";
		ContractBillMode contractBillMode = new ContractBillMode();
		contractBillMode.setAgent(agent);
		contractBillMode.setCwRootPcode(getBizConfigByKey(YdzbdataSyncConstants.cwRootEnumPCode));
		long count = StatementQueryUtil.queryCount(countQuerySql,connection,startDate,endDate);
		int totalPage = (int)Math.ceil((double)count / 100);
		for(int i = 0; i < totalPage;i++) {
			List<Map<String, Object>> gztdDataList = StatementQueryUtil.queryList(pageQuerySql, connection, i*100);
			for (Map<String, Object> rowMap : gztdDataList) {
				Map<String, Object> targetMap = new HashMap<>();
				contractBillMode.preProcess(rowMap);
				contractBillMode.transfer(targetMap,rowMap);
				insertData(getBizConfigByKey(YdzbdataSyncConstants.feeFormNo),convert2StringValue(targetMap));
			}
		}
		log.info("合同费用数据同步完成");
	}

	private Map<String,String> convert2StringValue(Map<String,Object> oriMap) {
		Map<String,String> resMap = new HashMap<>();
		for (String key : oriMap.keySet()) {
			resMap.put(key,oriMap.get(key)+"");
		}
		return resMap;
	}

	//处理水电费
	private void processHydpowerRechargeData(Connection connection,Date startDate,Date endDate) throws SQLException, BusinessException, ServiceException {
		log.info("开始同步水电费数据");
		String countQuerySql = "SELECT count(*) FROM zb_hydropower_recharge where recharge_time >= ? and recharge_time <=;";
		String pageQuerySql = "SELECT * FROM zb_hydropower_recharge where recharge_time >= ? and recharge_time <= ? limit 100 OFFSET ?;";
		HydropowerRechargeDataMapMode rechargeDataMapMode = new HydropowerRechargeDataMapMode();
		rechargeDataMapMode.setAgent(agent);
		rechargeDataMapMode.setCwRootPcode(getBizConfigByKey(YdzbdataSyncConstants.cwRootEnumPCode));
		long count = StatementQueryUtil.queryCount(countQuerySql,connection, startDate,endDate);
		int totalPage = (int)Math.ceil((double)count / 100);
		for(int i = 0; i < totalPage;i++) {
			List<Map<String, Object>> dataList = StatementQueryUtil.queryList(pageQuerySql, connection, startDate,endDate,i*100);
			for (Map<String, Object> rowMap : dataList) {
				Map<String, Object> targetMap = new HashMap<>();
				rechargeDataMapMode.preProcess(rowMap);
				rechargeDataMapMode.transfer(targetMap,rowMap);
				insertData(getBizConfigByKey(YdzbdataSyncConstants.feeFormNo),convert2StringValue(targetMap));
			}
		}
		log.info("水电费数据同步完成");
	}

	//处理退费
	private void processRefundData(Connection connection,Date startDate,Date endDate) throws SQLException, BusinessException, ServiceException {
		log.info("开始同步退费数据");
		String countQuerySql = "SELECT count(*) FROM zb_refund where create_time >= ? and create_time <= ?;";
		String pageQuerySql = "SELECT * FROM zb_contract_bill where create_time >= ? and create_time <= ? limit 100 OFFSET ?;";
		RefundDataMapMode refundDataMapMode = new RefundDataMapMode();
		refundDataMapMode.setAgent(agent);
		refundDataMapMode.setCwRootPcode(getBizConfigByKey(YdzbdataSyncConstants.cwRootEnumPCode));
		long count = StatementQueryUtil.queryCount(countQuerySql,connection, startDate,endDate);
		int totalPage = (int)Math.ceil((double)count / 100);
		for(int i = 0; i < totalPage;i++) {
			List<Map<String, Object>> dataList = StatementQueryUtil.queryList(pageQuerySql,connection, startDate,endDate,i*100);
			for (Map<String, Object> rowMap : dataList) {
				Map<String, Object> targetMap = new HashMap<>();
				refundDataMapMode.preProcess(rowMap);
				refundDataMapMode.transfer(targetMap,rowMap);
				insertData(getBizConfigByKey(YdzbdataSyncConstants.feeFormNo),convert2StringValue(targetMap));
			}
		}
		log.info("退费数据同步结束");
	}

	//处理资产数据
	private void processZcData(Connection connection) throws SQLException, BusinessException, ServiceException {
		log.info("开始同步资产表数据");
		processBzfHouseData(connection);
		processGzcfData(connection);
		processGzfwData(connection);
		processGztdData(connection);
		log.info("资产表数据同步结束");
	}

	private void processGztdData(Connection connection) throws SQLException, BusinessException, ServiceException {
		log.info("开始同步国资土地数据");
		String countQuerySql = "SELECT count(*) FROM zb_gztd_house;";
		String pageQuerySql = "SELECT * FROM zb_gztd_house limit 100 OFFSET ?;";
		GztdAssetMode gztdAssetMode = new GztdAssetMode();
		gztdAssetMode.setAgent(agent);
		gztdAssetMode.setZcRootPcode(getBizConfigByKey(YdzbdataSyncConstants.zcRootEnumPCode));
		long count = StatementQueryUtil.queryCount(countQuerySql,connection, null);
		int totalPage = (int)Math.ceil((double)count / 100);
		for(int i = 0; i < totalPage;i++) {
			List<Map<String, Object>> dataList = StatementQueryUtil.queryList(pageQuerySql, connection, i*100);
			for (Map<String, Object> rowMap : dataList) {
				Map<String, Object> targetMap = new HashMap<>();
				gztdAssetMode.preProcess(rowMap);
				gztdAssetMode.transfer(targetMap,rowMap);
				upsertData(getBizConfigByKey(YdzbdataSyncConstants.zcFormNo),
							convert2StringValue(targetMap),
							getBizConfigByKey(YdzbdataSyncConstants.zcFormNo),
						"WHERE field0031 = ?",
						targetMap.get("资产编号") +"");
			}
		}
		log.info("国资土地数据同步完成");
	}

	private void processGzfwData(Connection connection) throws SQLException, BusinessException, ServiceException {
		log.info("开始同步国资房屋数据");
		String countQuerySql = "SELECT count(*) FROM zb_gzfw_house;";
		String pageQuerySql = "SELECT * FROM zb_gzfw_house limit 100 OFFSET ?;";
		GzfwAssetMode gzfwAssetMode = new GzfwAssetMode();
		gzfwAssetMode.setAgent(agent);
		gzfwAssetMode.setZcRootPcode(getBizConfigByKey(YdzbdataSyncConstants.zcRootEnumPCode));
		long count = StatementQueryUtil.queryCount(countQuerySql,connection, null);
		int totalPage = (int)Math.ceil((double)count / 100);
		for(int i = 0; i < totalPage;i++) {
			List<Map<String, Object>> dataList = StatementQueryUtil.queryList(pageQuerySql, connection, i*100);
			for (Map<String, Object> rowMap : dataList) {
				Map<String, Object> targetMap = new HashMap<>();
				gzfwAssetMode.preProcess(rowMap);
				gzfwAssetMode.transfer(targetMap,rowMap);
				upsertData(getBizConfigByKey(YdzbdataSyncConstants.zcFormNo),
						convert2StringValue(targetMap),
						getBizConfigByKey(YdzbdataSyncConstants.zcTable),
						"WHERE field0031 = ?",
						targetMap.get("资产编号") + "");
			}
		}
		log.info("国资房屋数据同步结束");
	}

	private void processGzcfData(Connection connection) throws SQLException, BusinessException, ServiceException {
		log.info("开始同步国资厂房数据");
		String countQuerySql = "SELECT count(*) FROM zb_gzcf_house;";
		String pageQuerySql = "SELECT * FROM zb_gzcf_house limit 100 OFFSET ?;";
		GzcfAssetMode gzcfAssetMode = new GzcfAssetMode();
		gzcfAssetMode.setAgent(agent);
		gzcfAssetMode.setZcRootPcode(getBizConfigByKey(YdzbdataSyncConstants.zcRootEnumPCode));
		long count = StatementQueryUtil.queryCount(countQuerySql,connection, null);
		int totalPage = (int)Math.ceil((double)count / 100);
		for(int i = 0; i < totalPage;i++) {
			List<Map<String, Object>> dataList = StatementQueryUtil.queryList(pageQuerySql, connection, i*100);
			for (Map<String, Object> rowMap : dataList) {
				Map<String, Object> targetMap = new HashMap<>();
				gzcfAssetMode.preProcess(rowMap);
				gzcfAssetMode.transfer(targetMap,rowMap);
				upsertData(getBizConfigByKey(YdzbdataSyncConstants.zcFormNo),
						convert2StringValue(targetMap),
						getBizConfigByKey(YdzbdataSyncConstants.zcTable),
						"WHERE field0031 = ?",
						targetMap.get("资产编号") + "");
			}
		}
		log.info("国资厂房数据同步完成");
	}

	private void processBzfHouseData(Connection connection) throws SQLException, BusinessException, ServiceException {
		log.info("开始同步保障房数据");
		String countQuerySql = "SELECT count(*) FROM zb_bzf_house;";
		String pageQuerySql = "SELECT * FROM zb_bzf_house limit 100 OFFSET ?;";
		BzfAssetMode bzfAssetMode = new BzfAssetMode();
		bzfAssetMode.setAgent(agent);
		bzfAssetMode.setZcRootPcode(getBizConfigByKey(YdzbdataSyncConstants.zcRootEnumPCode));
		long count = StatementQueryUtil.queryCount(countQuerySql,connection, null);
		int totalPage = (int)Math.ceil((double)count / 100);
		for(int i = 0; i < totalPage;i++) {
			List<Map<String, Object>> dataList = StatementQueryUtil.queryList(pageQuerySql, connection, i*100);
			for (Map<String, Object> rowMap : dataList) {
				Map<String, Object> targetMap = new HashMap<>();
				Map<String,Object> temp = new HashMap<>();
				temp.putAll(rowMap);
				temp.put("loginName",getBizConfigByKey(YdzbdataSyncConstants.loginName));
				temp.put("zcTable",getBizConfigByKey(YdzbdataSyncConstants.zcTable));
				bzfAssetMode.preProcess(temp);
				bzfAssetMode.transfer(targetMap,temp);
				upsertData(getBizConfigByKey(YdzbdataSyncConstants.zcFormNo),
						convert2StringValue(targetMap),
						getBizConfigByKey(YdzbdataSyncConstants.zcTable),
						"WHERE field0031 = ?",
						targetMap.get("资产编号") + "");
			}
		}
		log.info("保障房数据同步结束");
	}

	private void upsertData(String formNo,Map<String, String> targetMap,String table,String whereSql,String param) throws BusinessException, SQLException, ServiceException {
		//不存在则插入，存在则更新
		List<String> params = new ArrayList<>();
		params.add(param);
		String querySql = "SELECT * FROM " + table + whereSql +";";
		Map<String,Object> existData = null;
        try {
            //agent.execute(querySql,params);
			existData = agent.resultSetToMap();
		} catch (Exception e) {

        }
		if(existData != null && existData.size() > 0) {
			for (String key : targetMap.keySet()) {
				existData.put(key,targetMap.get(key)+"");
				Map<String, Object> updateSqlMap = generateUpdateSql(existData, table, whereSql, param);
				agent.execute((String) updateSqlMap.get("sql"),updateSqlMap.get("params"));
			}
		}else {
			FormExport formExport = new FormExport();
			formExport.setValues(FormExportUtil.setFormValue(targetMap));
			getFormFactory().importBusinessFormData(getBizConfigByKey(YdzbdataSyncConstants.loginName), formNo,formExport, new String[] {});
		}

	}

	private void insertData(String formNo,Map<String, String> targetMap) throws BusinessException, SQLException, ServiceException {
		FormExport formExport = new FormExport();
		formExport.setValues(FormExportUtil.setFormValue(targetMap));
		getFormFactory().importBusinessFormData(getBizConfigByKey(YdzbdataSyncConstants.loginName), formNo,formExport, new String[] {});
	}

	private void upsertData(String formNo,Map<String, String> targetMap,String table,Map<String, String> subTableMap,String whereSql,String param) throws BusinessException, SQLException, ServiceException {
		//不存在则插入，存在则更新
		List<String> params = new ArrayList<>();
		params.add(param);
		String querySql = "SELECT * FROM " + table + whereSql +";";
		Map<String,Object> existData = null;
		try {
			agent.execute(querySql,params);
			existData = agent.resultSetToMap();
		} catch (Exception e) {

		}
		if(existData != null && existData.size() > 0) {
			for (String key : targetMap.keySet()) {
				existData.put(key,targetMap.get(key)+"");
				Map<String, Object> updateSqlMap = generateUpdateSql(existData, table, whereSql, param);
				agent.execute((String) updateSqlMap.get("sql"),updateSqlMap.get("params"));
			}
		}else {
			FormExport formExport = new FormExport();
			formExport.setValues(FormExportUtil.setFormValue(targetMap));
			formExport.setSubordinateForms(FormExportUtil.setSubordinateFormValue(subTableMap));
			getFormFactory().importBusinessFormData(getBizConfigByKey(YdzbdataSyncConstants.loginName), formNo,formExport, new String[] {});
		}

	}

	private Map<String, Object> generateUpdateSql(Map<String, Object> fieldValues, String tableName, String whereClause,String clauseValue) {
		if (fieldValues == null || fieldValues.isEmpty()) {
			throw new IllegalArgumentException("Field values cannot be null or empty");
		}
		if (tableName == null || tableName.trim().isEmpty()) {
			throw new IllegalArgumentException("Table name cannot be null or empty");
		}
		if (whereClause == null || whereClause.trim().isEmpty()) {
			throw new IllegalArgumentException("Where clause cannot be null or empty");
		}
		StringBuilder sqlBuilder = new StringBuilder("UPDATE ").append(tableName).append(" SET ");
		List<Object> params = new ArrayList<>();
		// Build the SET clause
		int fieldCount = 0;
		for (Map.Entry<String, Object> entry : fieldValues.entrySet()) {
			if (fieldCount > 0) {
				sqlBuilder.append(", ");
			}
			sqlBuilder.append(entry.getKey()).append(" = ?");
			params.add(entry.getValue());
			fieldCount++;
		}
		params.add(clauseValue);
		// Append the WHERE clause
		sqlBuilder.append(whereClause);
		// Create result map
		Map<String, Object> result = new HashMap<>();
		result.put("sql", sqlBuilder.toString());
		result.put("params", params);
		return result;
	}

	@Override
	public void destroy() throws Exception {
		ydzbThirdDataSource.close();
	}

	private String getBizConfigByKey(YdzbdataSyncConstants key) {
		ConfigVo config = cstConfigApi.getConfig(getPluginId());
		if(prod) {
			return config.getParamVal(key.name());
		}else {
			return key.getDefaultValue();
		}
	}
}
