package com.ag.base;

//import com.ag.util.Page;

import com.ag.util.StrUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.SingleColumnRowMapper;
import org.springframework.util.CollectionUtils;

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

public abstract class BaseDAO<T> implements IBaseRepository<T> {

	@Override
	public abstract JdbcTemplate getJdbcTemplate();
	protected abstract SqlUtil<T> getSqlUtil();
	protected Logger logger = LoggerFactory.getLogger(getClass());

	@Override
	public int update(String sql, Object... params)
			throws DataAccessException {
		logger.info(StrUtil.join("sql==\n", sql));
		return this.getJdbcTemplate().update(sql, params);
	}

	@Override
	public T get(String sql, Class<T> returnType, Object... params)
			throws DataAccessException {
		RowMapper<T> rowMapper = new BeanPropertyRowMapper<>(returnType);
		logger.info( sql);
		List<T> l = this.getJdbcTemplate().query(sql, params, rowMapper);
		if (l.isEmpty()) {
			return null;
		} else {
			return l.get(0);
		}
		// return this.jdbcTemplate.queryForObject(sql, rowMapper, params);
	}

	@Override
	public List<T> list(String sql, Class<T> returnType, Object... params)
			throws DataAccessException {
		RowMapper<T> rowMapper = new BeanPropertyRowMapper<>(returnType);
		logger.info( sql);
		return this.getJdbcTemplate().query(sql, rowMapper, params);
	}

	private List<T> list(String sql, Class<T> returnType)
			throws DataAccessException {
		RowMapper<T> rowMapper = new BeanPropertyRowMapper<>(returnType);
		logger.info( sql);
		return this.getJdbcTemplate().query(sql, rowMapper);
	}

	@Override
	public List<T> listSingleColumn(String sql, Class<T> returnType,
									Object... params) throws DataAccessException {
		RowMapper<T> rowMapper = new SingleColumnRowMapper<>(returnType);
		return this.getJdbcTemplate().query(sql, rowMapper, params);
	}

	// protected int count(String sql, List<Object> params)
	// throws DataAccessException {
	// return this.jdbcTemplate.queryForObject(sql, params.toArray(),
	// Integer.class);
	// }

	@Override
	public int count(String sql, Object... params)
			throws DataAccessException {
		return this.getJdbcTemplate().queryForObject(sql, params, Integer.class);
	}

	/*public List<T> queryByPage(String sql, Class<T> returnType, Page page) {
		String count_sql = StringUtils.join("select count(0) from (",sql,") as t");
		page.setCount(this.count(count_sql));
		if(page.getCount() == 0){
			return null;
		}
		sql = StringUtils.join(sql,IBaseRepository.limit_sql);
		return this.list(sql, returnType, page.getOffset(),
				page.getRows());
	}*/

	/*public List<T> queryByPage(String sql, Class<T> returnType, Page page, Object... params) {
		if(params == null){
			queryByPage(sql, returnType, page);
		}
		//记录数
		String count_sql = StringUtils.join("select count(0) from (",sql,") as t");
		page.setCount(this.count(count_sql, params));
		if(page.getCount() == 0){
			return null;
		}
		//对象列表
		Object[] paramsAddPage = paramAddPage(page, params);
		sql = StringUtils.join(sql,IBaseRepository.limit_sql);
		return this.list(sql, returnType, paramsAddPage);
	}*/

	/*private Object[] paramAddPage(Page page, Object... params){
		List<Object> lst = new ArrayList<Object>();
		for(Object obj : params){
			lst.add(obj);
		}
		lst.add(page.getOffset());
		lst.add(page.getRows());
		return lst.toArray();
	}*/

	/*public static void main(String[] args) {
		String sql = "select * from t_default_cc where id=? and name=?";
		IBaseRepository<DefaultCc> base = new BaseRepositoryImpl<DefaultCc>();
		base.queryByPage(sql, DefaultCc.class, new Page(), 37, "ddskm");
	}*/

	@Override
	public int save(T t) {
		String sql = getSqlUtil().getSaveSql(t);
		return update(sql);
	}

	@Override
	public int update(T t, Object... param) {
		String sql = getSqlUtil().getUpdateSql(t, param);
		return update(sql);
	}

	@Override
	public int update(T t, String[] needUpdCol, Object... param) {
		String sql = getSqlUtil().getUpdateSql(t, needUpdCol, param);
		return update(sql);
	}

	@Override
	public int deleteStatus(T t, String pkColName, String deleteColName) {
		String sql = getSqlUtil().getDeleteSql(t, pkColName, deleteColName);
		return update(sql);
	}

//	public int delete(T t, String pkColName) {
//		String sql = getSqlUtil().deleteSql(t, pkColName);
//		return this.getJdbcTemplate().update(sql);
//	}

	@Override
	public int delete(T t, Object... colNames){
		String sql = getSqlUtil().deleteEqSql(t, colNames);
		return update(sql);
	}

	@Override
	public T findById(T t, Class<T> returnType, String pkColName) {
		String sql = getSqlUtil().getFindSql(t,  pkColName);
		return get(sql, returnType);
	}

	//全表查询
	@Override
	public List<T> findAll(Class<T> returnType) {
		String sql = getSqlUtil().getFindAllSql(returnType);
		return list(sql, returnType);
	}

	/**
	 * 指定where条件查询示例
	 * @Autowired
	   private DefaultBussniessImpl bizDao;//spring注入
	 *************************************************
	 * BaseCategory bc = new BaseCategory();
	 * bc.setTenancyId("b00");
	 * List<BaseCategory> bcs = bizDao.findByEqCriteria(bc, BaseCategory.class, "tenancy_Id", "byagent");
	 *
	 * 执行sql查询：  select * from base_category where  byagent=null and tenancy_Id='b00'
	 * @param entity 目标sql的对象映射
	 * @param returnType 返回类型
	 * @param colName 查询列（数组）
	 * @return 查询list
	 */
	@Override
	@Deprecated
	public List<T> findByEqCriteria(T entity, Class<T> returnType, Object... colName) {
		String sql = findByEqSql(entity, colName);
		return list(sql, returnType);
	}

	@Override
	@Deprecated
	public String findByEqSql(T entity, Object... colName) {
		return getSqlUtil().getEqCriteriaSql(entity, colName);
	}

	@Override
	public List<T> findByEntity(T entity, Class<T> returnType, boolean isAllTable) {
		String sql = getSelectByEntity(entity, isAllTable);
		return list(sql, returnType);
	}

	/**
	 * 动态where条件查询示例
	 * @Autowired
	   private DefaultBussniessImpl bizDao;//spring注入
	 *************************************************
	 * BaseCategory bc = new BaseCategory();
	 * bc.setId("a");
	 * bc.setIsAll((short)55);
	 * List<BaseCategory> bcs = bizDao.findByEntity(bc, BaseCategory.class);
	 *
	 * 执行sql查询：  select * from base_category where  id='a' and is_all=55
	 * @param entity 目标sql的对象映射
	 * @param returnType 返回类型
	 * @return 查询list
	 */
	@Override
	public List<T> findByEntity(T entity, Class<T> returnType) {
		String sql = getSelectByEntity(entity, false);
		return list(sql, returnType);
	}

	@Override
	public String getSelectByEntity(T entity, boolean isAllTable) {
		return getSqlUtil().getSelectByEntity(entity, isAllTable);
	}

	@Override
	public int findByCount(T entity, Object... colName){
		String sql = "select count(0) from (" + findByEqSql(entity, colName) + ") tab";
		return count(sql);
	}

	private int[] batchUpdate(String... sql){
		/**/
		String mylog = "##batchSql start \n";

		//sql打印，最多10条
		int logMax = sql.length > 10 ? 10 : sql.length;
		for (int i = 0; i < logMax; i++){
			mylog = StrUtil.join(mylog, sql[i]);
		}
		mylog = StrUtil.join(mylog, "\n total update records is "+sql.length);
		logger.info(mylog);

		int pageSize = 1000;
		if (sql.length <= pageSize){
			this.getJdbcTemplate().batchUpdate(sql);
			logger.info("update complete "+sql.length);
		} else {
			int currPage = 0;
			while (true){
				int begin = currPage * pageSize;
				int end = (currPage + 1) * pageSize;
				if (end > sql.length) {
					end = sql.length;
				}
				this.getJdbcTemplate().batchUpdate(getPageSql(sql, begin, end));
				logger.info("Update complete from {} to {}", begin+1, end);
				if (end >= sql.length){
					break;
				}
				currPage ++;
			}
		}
		logger.info("batchSql end##");
		return null;
	}

	private String[] getPageSql(String[] sql, int begin, int end){
		List<String> sqls = new ArrayList<>();
		for (int i = begin; i < end; i++){
			sqls.add(sql[i]);
		}
		return sqls.toArray(new String[0]);

	}

	@Override
	public int[] saveAll(List<T> lst){
		if(CollectionUtils.isEmpty(lst)){
			return null;
		}
		String[] sqls = new String[lst.size()];
		for(int i=0; i<sqls.length; i++){
			sqls[i] = getSqlUtil().getSaveSql(lst.get(i));
		}
		return this.batchUpdate(sqls);
	}
	@Override
	public int[] updateAll(List<T> lst, Object... colName){
		return updateAll(lst, null, colName);
	}
	@Override
	public int[] updateAll(List<T> lst, String[] needUpdCol, Object... colName){
		if(CollectionUtils.isEmpty(lst)){
			return null;
		}
		String[] sqls = new String[lst.size()];
		for(int i=0; i<sqls.length; i++){
			sqls[i] = getSqlUtil().getUpdateSql(lst.get(i), needUpdCol, colName);
		}
		return this.batchUpdate(sqls);
	}
	@Override
	public int[] deleteAll(List<T> lst, Object... colNames){
		if(CollectionUtils.isEmpty(lst)){
			return null;
		}
		String[] sqls = new String[lst.size()];
		for(int i=0; i<sqls.length; i++){
			sqls[i] = getSqlUtil().deleteEqSql(lst.get(i), colNames);
		}
		return this.batchUpdate(sqls);
	}

	@Override
	public List<Map<String, Object>> queryForList(String sql, Object... args){
		return getJdbcTemplate().queryForList(sql, args);
	}

	@Override
	public List<T> findInIds(Class<T> tClz, String ids, String idColName){
		List<T> result = new ArrayList<>();
		if (StrUtil.isEmpty(ids)){
			return result;
		}
		int pageSize = 1000;
		String[] array = ids.split(",");
		if (array.length <= pageSize){
			String sql = getSqlUtil().findInIds(tClz, ids, idColName);
			return list(sql, tClz);
		}
		List<String> pageIds = new ArrayList<>();
		String sb = "";
		for (int i=0; i<array.length; i++){
			sb = StrUtil.join(sb, array[i], ",");
			if ((i+1) % pageSize == 0){
				pageIds.add(sb.substring(0, sb.length()-1));
				sb = "";
			} else if (i == array.length-1){
				pageIds.add(sb.substring(0, sb.length()-1));
			}
		}
		for (String pageId : pageIds){
			String sql = getSqlUtil().findInIds(tClz, pageId, idColName);
			result.addAll(list(sql, tClz));
		}
		return result;

	}

	/*public static void main(String[] args) {
		String ids = "a,b,c,d,e,f,g,h";
		int pageSize = 8;
		String[] array = ids.split(",");
		String sb = "";
		List<String> pageIds = new ArrayList<>();
		for (int i=0; i<array.length; i++){
			sb = StrUtil.join(sb, array[i], ",");
			if ((i+1) % pageSize == 0){
				pageIds.add(sb.substring(0, sb.length()-1));
				sb = "";
			} else if (i == array.length-1){
				pageIds.add(sb.substring(0, sb.length()-1));
			}
		}
		for (String id : pageIds){
			System.out.println(id);
		}
	}*/


}