package com.its.pis.dao.mapper;

import com.its.app.utils.Elapsed;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Data
@Slf4j
public abstract class BatchDaoService {

    protected final int MAX_BATCH_SIZE = 1000;

    protected final SqlSessionFactory sqlSessionFactory;
    protected String serviceName;
    protected String mapperName;
    protected String mapper;
    protected int count;

    public BatchDaoService(SqlSessionFactory sqlSessionFactory) {
        this.sqlSessionFactory = sqlSessionFactory;
    }

    public int getCount() {
        return this.count;
    }
    public String getMapper() {
        return this.mapper;
    }
    public String getServiceName() {
        return this.serviceName;
    }
    public String getMapperName() {
        return this.mapperName;
    }

    public int execute(String mapper) {
        log.info("{}.insertBatch: {}: START.", this.serviceName, mapper);

        this.mapper = mapper;
        String mapperName = this.mapperName + this.mapper;
        Elapsed elapsed = new Elapsed();
        int total = 0;
        SqlSession sqlSession = null;
        try {
            sqlSession = this.sqlSessionFactory.openSession(ExecutorType.SIMPLE, false);
            total = sqlSession.update(mapperName);
        }
        finally {
            if (sqlSession != null) {
                sqlSession.commit();
                sqlSession.close();
            }
        }
        log.info("{}.insertBatch: {}: ..END. {} EA. {} ms.", this.serviceName, mapper, total, elapsed.milliSeconds());
        return total;
    }

    public int insertBatch(String mapper, List<HashMap<String, Object>> lists) {
        //log.info("{}.insertBatch: {}: START.", this.serviceName, mapper);
        this.mapper = mapper;
        String mapperName = this.mapperName + this.mapper;
        //Elapsed elapsed = new Elapsed();
        int total = lists.size();
        if (total == 0) {
            log.info("{}.insertBatch: {}: Data size zero.", this.serviceName, mapper);
            return 0;
        }
        int jobCnt = 0;
        SqlSession sqlSession = null;
        try {
            sqlSession = this.sqlSessionFactory.openSession(ExecutorType.BATCH, false);
            for (Map<String, Object> param : lists) {
                sqlSession.insert(mapperName, param);
                jobCnt++;
                if (jobCnt % this.MAX_BATCH_SIZE == 0 || jobCnt == total) {
                    sqlSession.flushStatements();
                    sqlSession.clearCache();
                }
            }
        }
        finally {
            if (sqlSession != null) {
                sqlSession.commit();
                sqlSession.close();
            }
        }
        this.count = total;
        //log.info("{}.insertBatch: {}: ..END. {} EA. {} ms.", this.serviceName, mapper, total, elapsed.milliSeconds());
        return this.count;
    }

    public int updateBatch(String mapper, List<HashMap<String, Object>> lists) {
        //log.info("{}.updateBatch: {}: START.", this.serviceName, mapper);
        this.mapper = mapper;
        String mapperName = this.mapperName + this.mapper;
        //Elapsed elapsed = new Elapsed();
        int total = lists.size();
        if (total == 0) {
            log.info("{}.updateBatch: {}: Data size zero.", this.serviceName, mapper);
            return 0;
        }
        int jobCnt = 0;
        SqlSession sqlSession = null;
        try {
            sqlSession = this.sqlSessionFactory.openSession(ExecutorType.BATCH, false);
            for (Map<String, Object> param : lists) {
                sqlSession.update(mapperName, param);
                jobCnt++;
                if (jobCnt % this.MAX_BATCH_SIZE == 0 || jobCnt == total) {
                    sqlSession.flushStatements();
                    sqlSession.clearCache();
                }
            }
        }
        finally {
            if (sqlSession != null) {
                sqlSession.commit();
                sqlSession.close();
            }
        }
        this.count = total;
        //log.info("{}.updateBatch: {}: ..END. {} EA. {} ms.", this.serviceName, mapper, total, elapsed.milliSeconds());
        return this.count;
    }

}
