package hib.fs.db.mssql;

import hib.fs.orm.EstablishEntityManager;
import hib.fs.utils.ColorUtilConstants;
import io.quarkus.runtime.Quarkus;
import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;
import jakarta.transaction.Transactional;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.Serial;
import java.io.Serializable;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

public class DodexDatabaseMssql extends DbMssql implements Serializable {
    @Serial
    private static final long serialVersionUID = 1L;
    private final static Logger logger = LoggerFactory.getLogger(DodexDatabaseMssql.class.getName());

    private static EntityManager em;
    private static EntityManagerFactory emf;
    private String dbName;

    public DodexDatabaseMssql() {
        super();
    }

    public void entityManagerSetup() {
        SessionFactory sessionFactory;
        Session session;

        try {
            em = EstablishEntityManager.getMssqlEmf().createEntityManager();

            session = em.unwrap(Session.class);
            if (session == null) {
                emf = EstablishEntityManager.getMssqlEmf();
                sessionFactory = EstablishEntityManager.getMssqlEmf().createEntityManager().unwrap(SessionFactory.class);
            }
        } catch (Exception ioe) {
            throw new RuntimeException(ioe.getMessage());
        }

        Map<String, Object> properties =
          Objects.requireNonNull(session).getProperties() != null ? session.getProperties(): new HashMap<>();
        Object sessionDbname = properties.get("database");
        dbName = sessionDbname != null ? sessionDbname.toString() : "dodex";
        Object mode = properties.get("mode");
    }

    public void entityManagerSetup(EntityManagerFactory emf) {
    }

    public void configDatabase() {
        String[] types = {"TABLE"};

        Session session = em.unwrap(Session.class);
        session.doWork(connection -> {
            try {
                connection.setAutoCommit(false);
                DatabaseMetaData databaseMetaData = connection.getMetaData();
                boolean didCreateATable = false;

                ResultSet rsDbname = databaseMetaData.getTables(dbName, null, "USERS", types);

                if (!rsDbname.next()) {
                    connection.createStatement().execute(getCreateTable("USERS"));
                    connection.createStatement().execute(getCreateTable("NAMEIDX"));
                    connection.createStatement().execute(getCreateTable("PASSWORDIDX"));
                    didCreateATable = true;
                    logger.info("{}Users Table Created.{}", ColorUtilConstants.GREEN, ColorUtilConstants.RESET);
                } else {
                    logger.info("{}Users Table Found.{}", ColorUtilConstants.GREEN, ColorUtilConstants.RESET);
                }
                rsDbname = databaseMetaData.getTables(dbName, null, "MESSAGES", types);
                if (!rsDbname.next()) {
                    connection.createStatement().execute(getCreateTable("MESSAGES"));
                    didCreateATable = true;
                    logger.info("{}Messages Table Created.{}", ColorUtilConstants.GREEN, ColorUtilConstants.RESET);
                } else {
                    logger.info("{}Messages Table Found.{}", ColorUtilConstants.GREEN, ColorUtilConstants.RESET);
                }
                rsDbname = databaseMetaData.getTables(dbName, null, "UNDELIVERED", types);
                if (!rsDbname.next()) {
                    connection.createStatement().execute(getCreateTable("UNDELIVERED"));
                    didCreateATable = true;
                    logger.info("{}Undelivered Table Created.{}", ColorUtilConstants.GREEN, ColorUtilConstants.RESET);
                } else {
                    logger.info("{}Undelivered Table Found.{}", ColorUtilConstants.GREEN, ColorUtilConstants.RESET);
                }
                rsDbname = databaseMetaData.getTables(dbName, null, "GROUPS", types);
                if (!rsDbname.next()) {
                    connection.createStatement().execute(getCreateTable("GROUPS"));
                    didCreateATable = true;
                    logger.info("{}Groups Table Created.{}", ColorUtilConstants.GREEN, ColorUtilConstants.RESET);
                } else {
                    logger.info("{}Groups Table Found.{}", ColorUtilConstants.GREEN, ColorUtilConstants.RESET);
                }
                rsDbname = databaseMetaData.getTables(dbName, null, "MEMBER", types);
                if (!rsDbname.next()) {
                    connection.createStatement().execute(getCreateTable("MEMBER"));
                    didCreateATable = true;
                    logger.info("{}Member Table Created.{}", ColorUtilConstants.GREEN, ColorUtilConstants.RESET);
                } else {
                    logger.info("{}Member Table Found.{}", ColorUtilConstants.GREEN, ColorUtilConstants.RESET);
                }
                rsDbname = databaseMetaData.getTables(dbName, null, "GOLFER", types);
                if (!rsDbname.next()) {
                    connection.createStatement().execute(getCreateTable("GOLFER"));
                    didCreateATable = true;
                    logger.info("{}Golfer Table Created.{}", ColorUtilConstants.GREEN, ColorUtilConstants.RESET);
                } else {
                    logger.info("{}Golfer Table Found.{}", ColorUtilConstants.GREEN, ColorUtilConstants.RESET);
                }
                rsDbname = databaseMetaData.getTables(dbName, null, "COURSE", types);
                if (!rsDbname.next()) {
                    connection.createStatement().execute(getCreateTable("COURSE"));
                    didCreateATable = true;
                    logger.info("{}Course Table Created.{}", ColorUtilConstants.GREEN, ColorUtilConstants.RESET);
                } else {
                    logger.info("{}Course Table Found.{}", ColorUtilConstants.GREEN, ColorUtilConstants.RESET);
                }
                rsDbname = databaseMetaData.getTables(dbName, null, "RATINGS", types);
                if (!rsDbname.next()) {
                    connection.createStatement().execute(getCreateTable("RATINGS"));
                    didCreateATable = true;
                    logger.info("{}Ratings Table Created.{}", ColorUtilConstants.GREEN, ColorUtilConstants.RESET);
                } else {
                    logger.info("{}Ratings Table Found.{}", ColorUtilConstants.GREEN, ColorUtilConstants.RESET);
                }
                rsDbname = databaseMetaData.getTables(dbName, null, "SCORES", types);
                if (!rsDbname.next()) {
                    connection.createStatement().execute(getCreateTable("SCORES"));
                    didCreateATable = true;
                    logger.info("{}Scores Table Created.{}", ColorUtilConstants.GREEN, ColorUtilConstants.RESET);
                } else {
                    logger.info("{}Scores Table Found.{}", ColorUtilConstants.GREEN, ColorUtilConstants.RESET);
                }
                if (didCreateATable) {
                    ResultSet rsSchemas = databaseMetaData.getCatalogs();
                    while (rsSchemas.next()) {
                        if (dbName.equals(rsSchemas.getString(1))) {
                            logger.warn("{}Used database: '{}' to Create Tables.{}",
                              ColorUtilConstants.YELLOW, dbName, ColorUtilConstants.RESET);
                        }
                    }
                }
                rsDbname.close();
                connection.commit();
                connection.close();
                Quarkus.asyncExit();

            } catch (SQLException se) {
                se.printStackTrace();
            }
        });
    }

    public static void quit() {
        Quarkus.asyncExit();
    }

    public EntityManagerFactory getEmf() {
        return emf;
    }
}
