package com.liquidnet.service.consumer.dragon.service.impl;

import com.liquidnet.commons.lang.util.JsonUtils;
import com.liquidnet.service.consumer.dragon.service.IBaseDao;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.PreparedStatementCreator;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.jdbc.support.KeyHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate;

import javax.annotation.Resource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.LinkedList;

@Service
public class BaseDao implements IBaseDao {
    private static final Logger log = LoggerFactory.getLogger(BaseDao.class);
    @Resource
    public JdbcTemplate jdbcTemplate;
    @Resource(name = "transactionManager")
    public DataSourceTransactionManager transactionManager;

    @Override
    public Boolean batchSql(final String sql, final LinkedList<Object[]> values) {
        TransactionCallback<Boolean> callback = transactionStatus -> {
            if (values.size() > 0) {
                int[] ints = jdbcTemplate.batchUpdate(sql, values);
            }
            return true;
        };
        try {
            TransactionTemplate tt = new TransactionTemplate(transactionManager);
            return tt.execute(callback);
        } catch (Exception ex) {
            log.error("###\nSQL.Preparing:{}\nParameters:{}", JsonUtils.toJson(sql), JsonUtils.toJson(values), ex);
            return false;
        }
    }

    @Override
    public Boolean batchSqls(final LinkedList<String> sql,
                             final LinkedList<Object[]>... values) {
        try {
            TransactionCallback<Boolean> callback = transactionStatus -> {
                int i = 0;
                for (LinkedList<Object[]> o : values) {
                    if (sql.size() < i + 1) {
                        break;
                    }
                    if (!o.isEmpty()) {
                        jdbcTemplate.batchUpdate(sql.get(i), o);
                    }
                    i++;
                }
                return true;
            };

            TransactionTemplate tt = new TransactionTemplate(transactionManager);
            return tt.execute(callback);
        } catch (Exception ex) {
            log.error("###Error.Sqls:{}\nParameters:{},Ex:{}", JsonUtils.toJson(sql), JsonUtils.toJson(values), ex.getMessage());
            return false;
        }
    }

    @Override
    public Boolean batchSqlNoArgs(final LinkedList<String> sql) {
        try {
            TransactionCallback<Boolean> callback = transactionStatus -> {
                for (String o : sql) {
                    jdbcTemplate.execute(o);
                }
                return true;
            };

            TransactionTemplate tt = new TransactionTemplate(transactionManager);
            return tt.execute(callback);
        } catch (Exception ex) {
            log.error("###Error.Sqls:{}\nParameters:{},Ex:{}", sql);
            return false;
        }
    }

    /**
     * xs 新增一条记录且返回主键Id
     *
     * @param sql   新增待执行sql
     * @param param 参数
     * @return 主键ID
     */
    public int insertSqlAndReturnKeyId(final String sql, final Object[] param) {
        final String innersql = sql;
        final Object[] innerO = param;
        KeyHolder keyHolder = new GeneratedKeyHolder();
        try {
            jdbcTemplate.update(con -> {
                PreparedStatement ps = con.prepareStatement(innersql,
                        Statement.RETURN_GENERATED_KEYS);
                for (int i = 0; i < innerO.length; i++) {
                    ps.setObject(i + 1, innerO[i]);
                }

                return ps;
            }, keyHolder);
        } catch (Exception e) {
            log.error("###\nSQL.Preparing:{}\nParameters:{}", sql, JsonUtils.toJson(param), e);
        }
        return keyHolder.getKey().intValue();

    }
}
