package study.runtime;

import java.sql.*;
import java.util.*;
import com.zaxxer.hikari.HikariDataSource;
import org.springframework.context.ConfigurableApplicationContext;

class DatabaseProbe {
  static Object run(ConfigurableApplicationContext context)throws Exception{
    var pool=context.getBean(HikariDataSource.class);var output=new LinkedHashMap<String,Object>();
    output.put("maxPoolSize",pool.getMaximumPoolSize());output.put("borrowTimeoutMillis",pool.getConnectionTimeout());
    try(var first=pool.getConnection()){
      try(var statement=first.createStatement();var rs=statement.executeQuery("SELECT 1")){
        if(!rs.next()||rs.getInt(1)!=1)throw new AssertionError("SELECT 1");
      }
      output.put("mysql",first.getMetaData().getDatabaseProductVersion());output.put("driver",first.getMetaData().getDriverVersion());
      long start=System.nanoTime();boolean failed=false;
      try(var unexpected=pool.getConnection()){throw new AssertionError("pool size1 did not limit borrowing");}
      catch(SQLTransientConnectionException expected){failed=true;output.put("failure",expected.getClass().getName());}
      long elapsed=TimeUnitMillis.since(start);if(!failed||elapsed<250||elapsed>3000)throw new AssertionError("unexpected borrow wait "+elapsed);
      output.put("observedWaitMillis",elapsed);
    }
    try(var recovered=pool.getConnection();var st=recovered.createStatement();var rs=st.executeQuery("SELECT 1")){
      if(!rs.next()||rs.getInt(1)!=1)throw new AssertionError("recovery failed");
      output.put("recovered",true);
    }
    return output;
  }
  static class TimeUnitMillis{static long since(long start){return java.util.concurrent.TimeUnit.NANOSECONDS.toMillis(System.nanoTime()-start);}}
}
