import java.lang.reflect.Proxy;
import java.sql.Connection;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.DriverPropertyInfo;
import java.sql.SQLException;
import java.util.Properties;

public class DiagnosisKoneksi {

    public static void main(String[] args) throws SQLException {
        DriverManager.registerDriver(new DemoDriver());

        // Batas waktu menyambung: koneksi menggantung lebih dari 3 detik dibatalkan
        DriverManager.setLoginTimeout(3);
        System.out.println("loginTimeout  : " + DriverManager.getLoginTimeout() + " detik");

        // Skenario 1: koneksi berhasil dengan kredensial lewat Properties
        Properties prop = new Properties();
        prop.setProperty("user", "budi");
        prop.setProperty("password", "rahasia");
        try (Connection conn = DriverManager.getConnection("jdbc:demo:toko", prop)) {
            System.out.println("koneksi       : TERBUKA sebagai " + prop.getProperty("user"));
        }

        // Skenario 2: koneksi gagal, diagnosis lewat SQLException
        try {
            Connection gagal = DriverManager.getConnection("jdbc:demo:galat");
            System.out.println("baris ini tidak pernah tercetak: " + gagal);
        } catch (SQLException e) {
            System.out.println("koneksi       : GAGAL");
            System.out.println("getMessage()  : " + e.getMessage());
            System.out.println("getSQLState() : " + e.getSQLState());
            System.out.println("getErrorCode(): " + e.getErrorCode());
        }
    }
}

class DemoDriver implements Driver {

    @Override
    public Connection connect(String url, Properties info) throws SQLException {
        if (url == null || !url.startsWith("jdbc:demo:")) {
            return null;
        }
        if (url.endsWith(":galat")) {
            // meniru kegagalan jaringan nyata pada database sungguhan
            throw new SQLException(
                    "Koneksi ditolak: host demo.toko.local tidak merespons",
                    "08001", 10061);
        }
        String user = (info == null) ? "-" : info.getProperty("user", "-");
        System.out.println("[shim] connect(" + url + ") user=" + user + " password=****");
        return (Connection) Proxy.newProxyInstance(
                Connection.class.getClassLoader(),
                new Class<?>[]{Connection.class},
                (proxy, method, argumen) -> {
                    if (method.getName().equals("close")) {
                        System.out.println("[shim] Connection.close()");
                        return null;
                    }
                    if (method.getName().equals("toString")) {
                        return "ShimConnection";
                    }
                    Class<?> t = method.getReturnType();
                    if (t == boolean.class) return false;
                    if (t == int.class) return 0;
                    return null;
                });
    }

    @Override
    public boolean acceptsURL(String url) {
        return url != null && url.startsWith("jdbc:demo:");
    }

    @Override
    public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) {
        return new DriverPropertyInfo[0];
    }

    @Override
    public int getMajorVersion() {
        return 1;
    }

    @Override
    public int getMinorVersion() {
        return 0;
    }

    @Override
    public boolean jdbcCompliant() {
        return false;
    }

    @Override
    public java.util.logging.Logger getParentLogger() {
        return null;
    }
}
