package com.qmth.boot.mybatis.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.qmth.boot.mybatis.config.MybatisProperties;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.support.AopUtils;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;

import java.util.Map;

@Component
public class DatabaseInitializeService implements ApplicationListener<ContextRefreshedEvent> {

    private static final Logger log = LoggerFactory.getLogger(DatabaseInitializeService.class);

    private static final String SQL_SPLITE = ";";

    private JdbcTemplate jdbcTemplate;

    private MybatisProperties mybatisProperties;

    public DatabaseInitializeService(JdbcTemplate jdbcTemplate, MybatisProperties mybatisProperties) {
        this.jdbcTemplate = jdbcTemplate;
        this.mybatisProperties = mybatisProperties;
    }

    @Override
    public synchronized void onApplicationEvent(ContextRefreshedEvent event) {
        if (event.getApplicationContext().getParent() == null) {
            //获取容器中的SqlProvider执行初始化sql
            initBySql(event);
            //若开启schema校验，则读取所有BaseMapper分别尝试select一条记录
            if (mybatisProperties.isSchemaValidate()) {
                schemaValidate(event);
            }
        }
    }

    private void initBySql(ContextRefreshedEvent event) {
        Map<String, SqlProvider> beans = event.getApplicationContext().getBeansOfType(SqlProvider.class);
        for (SqlProvider provider : beans.values()) {
            String beanName = AopUtils.getTargetClass(provider).getName();
            String content = StringUtils.trimToNull(provider.get());
            if (content == null) {
                throw new RuntimeException("Blank content from SqlProvider: " + beanName);
            }
            String[] lines = StringUtils.split(content, SQL_SPLITE);
            int count = 0;
            for (String sql : lines) {
                if (StringUtils.isNotBlank(sql)) {
                    jdbcTemplate.execute(sql);
                    count++;
                }
            }
            log.info("Database initialize from SqlProvider: {}, execute count: {}", beanName, count);
        }
    }

    private void schemaValidate(ContextRefreshedEvent event) {
        Map<String, BaseMapper> beans = event.getApplicationContext().getBeansOfType(BaseMapper.class);
        for (BaseMapper mapper : beans.values()) {
            QueryWrapper wrapper = new QueryWrapper();
            wrapper.last("limit 1");
            mapper.selectOne(wrapper);
            log.info("MybatisPlus schema validate: {}", mapper.getClass().getGenericInterfaces()[0].getTypeName());
        }
    }
}
