package org.springblade.sqlfly.opt;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;

import org.springblade.bi.client.model.DataSourceModel;
import org.springblade.flow.database.exception.DataException;
import org.springblade.flow.database.model.DbLinkEntity;
import org.springblade.flow.database.util.JdbcUtil;
import org.springblade.sqlfly.config.Column;
import org.springblade.sqlfly.config.DbConfig;
import org.springblade.sqlfly.config.DbType;
import org.springblade.sqlfly.config.Table;

import com.alibaba.fastjson2.JSON;
import com.fly.jdbc.SqlFly;
import com.fly.jdbc.SqlFlyFactory;
import com.fly.jdbc.cfg.FlyConfig;
import com.fly.jdbc.cfg.FlyObjects;
import com.fly.jdbc.datasource.FlyDataSource;

import cn.hutool.core.collection.CollUtil;
import lombok.extern.slf4j.Slf4j;

/**
 * 数据库操作抽象类
 * 
 * @author William
 * @date 2022年10月28日 上午11:30:22
 */
@Slf4j
public abstract class IFly {

	protected static SqlFly fly;
	protected static DbConfig db;

	public static IFly get(DataSourceModel source) {
		fly = SqlFlyFactory.getSqlFly();
		db = DbConfig.get(source);
		if (db != null) {
			init(fly, db);
			log.info("db config is: " + JSON.toJSONString(db));
		} else {
			log.info("db config is null");
		}

		DbType dbType = db.getDbType();
		switch (dbType) {
		case clickhouse:
			return new FlyClickhouse();
		case oracle:
			return new FlyOracle();
		case postgresql:
			return new FlyPostgre();
		case mysql:
			return new FlyMysql();
		default:
			return null;
		}
	}

	private static void init(SqlFly fly, DbConfig db) {
		FlyConfig flyConfig = new FlyConfig();
		flyConfig.setUrl(db.getUrl());
		flyConfig.setUsername(db.getUser());
		flyConfig.setPassword(db.getPassword());
		flyConfig.setDriverClassName(db.getDriver());
		FlyObjects.setConfig(flyConfig);

		FlyDataSource dataSource = new FlyDataSource(db.getDriver(), db.getUrl(), db.getUser(), db.getPassword(), false,
				1, 1, 1);
		fly.setDataSource(dataSource);
	}

	protected IFly() {
	}

	public Map<String, Object> getMap(String sql, Object... args) {
		return fly.getMap(sql, args);
	}

	public List<Map<String, Object>> getMapList(String sql, Object... args) {
		return fly.getMapList(sql, args);
	}

	public Connection getTableConn(DbLinkEntity link) throws SQLException {
		Connection conn = null;
		if (link != null) {
			try {
				conn = JdbcUtil.getConn(link);
			} catch (DataException e) {
				e.printStackTrace();
			}
		}
		if (conn == null) {
			throw new SQLException("连接数据库失败");
		}
		return conn;
	}

	public Column getPrimaryColumn(String tableName) {
		List<Column> colList = getColumnList(tableName);
		if (CollUtil.isNotEmpty(colList)) {
			for (Column col : colList) {
				if (col.getPrimaryKey()) {
					return col;
				}
			}
		}
		return null;
	}

	/**
	 * 获取所有表
	 * 
	 * @param schema 某些数据库需要
	 * @return
	 */
	public abstract List<Table> getTableList(String schema);

	/**
	 * 获取某个表
	 * 
	 * @param schema 某些数据库需要
	 * @param tableName 表名
	 * @return
	 */
	public abstract Table getTable(String schema, String tableName);

	/**
	 * 获取所有列
	 * 
	 * @return
	 */
	public abstract List<Column> getColumnList(String tableName);
}
