package cn.ibizlab.core.extensions.service;

import cn.ibizlab.core.lite.domain.DstDataSource;
import cn.ibizlab.core.lite.extensions.domain.Setting;
import cn.ibizlab.core.lite.extensions.domain.SysModel;
import cn.ibizlab.core.lite.service.impl.DstDataSourceServiceImpl;
import cn.ibizlab.util.domain.LiquibaseProp;
import cn.ibizlab.util.errors.BadRequestAlertException;
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 org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 实体[数据源] 自定义服务对象
 */
@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);
    }

    /**
     * [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;
    }

}

