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

import com.liquidnet.commons.lang.util.JsonUtils;
import com.liquidnet.service.consumer.goblin.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 = new TransactionCallback<Boolean>() {
            @Override
            public Boolean doInTransaction(final TransactionStatus 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 = new TransactionCallback<Boolean>() {
                @Override
                public Boolean doInTransaction(final TransactionStatus 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) {
//            if (ex instanceof LiquidnetServiceException) {
//                log.error("###Error.Code:{} - {}", ((LiquidnetServiceException) ex).getCode(), ex.getMessage());
//            } else {
            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 = new TransactionCallback<Boolean>() {
                @Override
                public Boolean doInTransaction(final TransactionStatus 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(new PreparedStatementCreator() {
                @Override
                public PreparedStatement createPreparedStatement(final Connection con)
                        throws SQLException {
                    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();

    }
}
