package cn.ibizlab.core.extensions.service;

import cn.ibizlab.core.lite.extensions.domain.SysModel;
import cn.ibizlab.core.lite.extensions.service.LiteCoreService;
import cn.ibizlab.core.lite.extensions.service.DstLiquibaseService;
import cn.ibizlab.core.lite.service.impl.DstDataSourceServiceImpl;
import cn.ibizlab.util.domain.LiquibaseProp;
import cn.ibizlab.util.errors.BadRequestAlertException;
import cn.ibizlab.util.helper.Setting;
import com.alibaba.fastjson.JSONArray;
import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
import com.baomidou.dynamic.datasource.creator.DataSourceCreator;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DataSourceProperty;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.extern.slf4j.Slf4j;
import cn.ibizlab.core.lite.domain.DstDataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.context.annotation.Primary;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.sql.DataSource;
import java.util.*;


/**
 * 实体[数据源] 自定义服务对象
 */
@Slf4j
@Primary
@Service("DstDataSourceExService")
public class DstDataSourceExService extends DstDataSourceServiceImpl {

    @Override
    protected Class currentModelClass() {
        return com.baomidou.mybatisplus.core.toolkit.ReflectionKit.getSuperClassGenericType(this.getClass().getSuperclass(), 1);
    }
    @Resource
    public LiteCoreService liteCoreService;

    @Resource
    public DstLiquibaseService dstLiquibaseService;


    /**
     * [BuildDS:buildDS] 行为扩展
     * @param dstDataSource
     * @return
     */
    @Override
    @Transactional
    public DstDataSource buildDS(DstDataSource dstDataSource) {

        if(dstDataSource!=null&&(!StringUtils.isEmpty(dstDataSource.getDsCfg())))
        {
            synchronized (lock)
            {
                if (check.containsKey(dstDataSource.getDsName()))
                    return super.buildDS(dstDataSource);

                if(!"mongodb".equalsIgnoreCase(dstDataSource.getDsType()))
                {
                    DataSourceProperty dataSourceProperty = new DataSourceProperty();
                    DynamicRoutingDataSource ds = dataSource;
                    List<Setting> settings = JSONArray.parseArray(dstDataSource.getDsCfg(), Setting.class);
                    for (Setting setting : settings)
                    {
                        if (setting.getProperty().equalsIgnoreCase("driver-class-name"))
                            dataSourceProperty.setDriverClassName(setting.getValue());
                        else if (setting.getProperty().equalsIgnoreCase("username"))
                            dataSourceProperty.setUsername(setting.getValue());
                        else if (setting.getProperty().equalsIgnoreCase("password"))
                            dataSourceProperty.setPassword(setting.getValue());
                        else if (setting.getProperty().equalsIgnoreCase("url"))
                            dataSourceProperty.setUrl(setting.getValue());
                        else if (setting.getProperty().equalsIgnoreCase("defaultSchema"))
                            dataSourceProperty.setSchema(setting.getValue());
                    }

                    dataSourceProperty.getDruid().setFilters("stat,log4j2");
                    DataSource dataSource = druidDataSourceCreator.createDataSource(dataSourceProperty);

                    ds.addDataSource(dstDataSource.getDsName(), dataSource);
                }

                check.put(dstDataSource.getDsName(), StringUtils.isEmpty(dstDataSource.getDsType())?"mysql":dstDataSource.getDsType());
            }
        }

        return super.buildDS(dstDataSource);
    }

    @Autowired
    @Lazy
    private DynamicRoutingDataSource dataSource;

    @Autowired
    @Lazy
    private DataSourceCreator druidDataSourceCreator;


    private HashMap<String,String> check=new HashMap<>();
    private Object lock=new Object();

    public synchronized String initDataSource(String dsName)
    {
        DstDataSource dstDataSource=null;
        synchronized (lock)
        {
            if (check.containsKey(dsName))
                return check.get(dsName);
            dstDataSource=this.getOne(Wrappers.<DstDataSource>lambdaQuery().eq(DstDataSource::getDsId,dsName).or().eq(DstDataSource::getDsName,dsName),false);
            if(dstDataSource!=null) dstDataSource.setDsName(dsName);
        }
        buildDS(dstDataSource);
        synchronized (lock)
        {
            return StringUtils.isEmpty(check.get(dsName))?"mysql":check.get(dsName);
        }
    }

    @Override
    public boolean update(DstDataSource et) {
        if(!super.update(et))
            return false;
        synchronized (lock)
        {
            DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource;
            if (check.containsKey(et.getDsId()))
            {
                if(!"mongodb".equalsIgnoreCase(check.get(et.getDsId())))
                    ds.removeDataSource(et.getDsId());
                check.remove(et.getDsId());
            }
            if (check.containsKey(et.getDsName()))
            {
                if(!"mongodb".equalsIgnoreCase(check.get(et.getDsName())))
                    ds.removeDataSource(et.getDsName());
                check.remove(et.getDsName());
            }
        }
        buildDS(et);

        return true;
    }

    @Override
    @Transactional
    public DstDataSource initDS(DstDataSource et) {
        DstDataSource ds = getById(et.getDsId());

        if(ObjectUtils.isEmpty(ds)){
            throw new BadRequestAlertException("数据源不存在，请检查是否填写正确","","ibzInit");
        }
        buildDS(ds);

        String datasourceMessage = ds.getDsCfg();

        if(ObjectUtils.isEmpty(datasourceMessage)){
            throw new BadRequestAlertException("数据源不能为空","","ibzInit");
        }
        List<Setting> settings = JSONArray.parseArray(ds.getDsCfg(), Setting.class);
        Map datasourceMap = new HashMap();
        settings.forEach(setting -> datasourceMap.put(setting.getProperty(),setting.getValue()));

        if(ObjectUtils.isEmpty(datasourceMap.get("username"))){
            throw new BadRequestAlertException("数据源用户名不能为空","","ibzInit");
        }
        if(ObjectUtils.isEmpty(datasourceMap.get("password"))){
            throw new BadRequestAlertException("数据源密码不能为空","","ibzInit");
        }
        if(ObjectUtils.isEmpty(datasourceMap.get("url"))){
            throw new BadRequestAlertException("数据源地址不能为空","","ibzInit");
        }
        if(ObjectUtils.isEmpty(datasourceMap.get("defaultSchema"))){
            throw new BadRequestAlertException("数据源默认数据库不能为空","","ibzInit");
        }

        if(ObjectUtils.isEmpty(datasourceMap.get("defaultSystemId"))){
            throw new BadRequestAlertException("逆向工程归属系统为空","","ibzInit");
        }
        LiquibaseProp lp = new LiquibaseProp();
        lp.setUsername(datasourceMap.get("username").toString());
        lp.setPassword(datasourceMap.get("password").toString());
        lp.setUrl(datasourceMap.get("url").toString());
        lp.setDefaultSchema(datasourceMap.get("defaultSchema").toString());
        // 调用liquibase逆向工程的逻辑，生成一个xml，并返回一个SysModel对象
        SysModel sysModel = dstLiquibaseService.generateLiquibase(lp,datasourceMap.get("defaultSystemId").toString());
        //liteCoreService.syncSysModel(sysModel,1);
        return et;
    }
}

