import com.pyranid.Database;
import com.pyranid.DatabaseType;
import com.pyranid.Notification;

import javax.sql.DataSource;
import java.time.Duration;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

/**
 * Manual-listener demonstration for Pyranid 4.8.0 and PostgreSQL.
 * Create and seed the feature_flag table from the Notifications documentation first.
 * Supply a session-affine DataSource with capacity for the listener and a query connection.
 * Call run on an application-owned thread; interrupt that thread to request a stop.
 * This low-level example does not reconnect or provide independent fallback polling.
 */
public final class FeatureFlagSession {
  public record FeatureFlag(String name, Boolean enabled) {}

  private FeatureFlagSession() {}

  public static void run(DataSource dataSource) {
    Database database = Database.with(dataSource, DatabaseType.POSTGRESQL)
      .build();
    AtomicReference<Map<String, Boolean>> flags =
      new AtomicReference<>(Map.of());

    Runnable reloadFlags = () -> {
      Map<String, Boolean> snapshot = database.query("""
        SELECT name, enabled
        FROM feature_flag
        """)
        .queryTimeout(Duration.ofSeconds(5))
        .fetchList(FeatureFlag.class)
        .stream()
        .collect(Collectors.toUnmodifiableMap(
          FeatureFlag::name, FeatureFlag::enabled));

      flags.set(snapshot);
      System.out.println("Refreshed feature flags: " + snapshot);
    };

    try {
      database.withNotificationSession(
        Set.of("feature_flag_changed", "feature_flag_removed"),
        session -> {
          // Registration has finished. Load the current durable state.
          reloadFlags.run();

          while (true) {
            List<Notification> hints =
              session.awaitNotifications(Duration.ofSeconds(30));
            boolean stopRequested = Thread.interrupted();

            try {
              if (!hints.isEmpty())
                reloadFlags.run();
            } finally {
              if (stopRequested)
                Thread.currentThread().interrupt();
            }
          }
        }
      );
    } catch (InterruptedException interruptedException) {
      // Preserve the cancelation signal for the caller.
      Thread.currentThread().interrupt();
    }
  }
}
