//! Cluster-0.25 leader TTL / heartbeat / failover-cap / reaper-interval
//! tunables. Verifies the builder methods thread the configured value
//! through to the dispatcher fields. The previous integration tests
//! (`leader_election.rs`, `failover_reinvoke.rs`) cover the effect on
//! actual claim + gate behaviour using the default constants; this
//! suite only proves the dial is wired.

#![cfg(feature = "http")]

use std::sync::Arc;
use std::time::Duration;

use klieo_a2a::handler::{A2aHandler, EchoHandler};
use klieo_a2a::server::{A2aDispatcher, LEADER_TTL};
use klieo_auth_common::{AllowAnonymous, Authenticator};
use klieo_bus_memory::MemoryBus;
use klieo_core::{KvStore, Pubsub, FAILOVER_ATTEMPT_CAP};

fn handler() -> Arc<dyn A2aHandler> {
    Arc::new(EchoHandler::default())
}

fn auth() -> Arc<dyn Authenticator> {
    Arc::new(AllowAnonymous)
}

fn pubsub() -> (Arc<dyn Pubsub>, Arc<dyn KvStore>) {
    let bus = MemoryBus::new();
    (bus.pubsub.clone(), bus.kv.clone())
}

#[tokio::test(flavor = "current_thread")]
async fn builder_with_leader_ttl_threads_through() {
    let (ps, kv) = pubsub();
    let dispatcher = A2aDispatcher::builder()
        .handler(handler())
        .authenticator(auth())
        .pubsub(ps)
        .with_leader_election(kv)
        .with_leader_ttl(Duration::from_secs(30))
        .build()
        .expect("test builder");
    assert_eq!(dispatcher.leader_ttl(), Duration::from_secs(30));
    // Heartbeat defaults to ttl / 2 when not explicitly set.
    assert_eq!(
        dispatcher.leader_heartbeat_interval(),
        Duration::from_secs(15)
    );
}

#[tokio::test(flavor = "current_thread")]
async fn builder_with_leader_heartbeat_interval_threads_through() {
    let (ps, kv) = pubsub();
    let dispatcher = A2aDispatcher::builder()
        .handler(handler())
        .authenticator(auth())
        .pubsub(ps)
        .with_leader_election(kv)
        .with_leader_ttl(Duration::from_secs(20))
        .with_leader_heartbeat_interval(Duration::from_millis(2500))
        .build()
        .expect("test builder");
    assert_eq!(dispatcher.leader_ttl(), Duration::from_secs(20));
    assert_eq!(
        dispatcher.leader_heartbeat_interval(),
        Duration::from_millis(2500),
        "explicit heartbeat must override the ttl/2 default",
    );
}

#[tokio::test(flavor = "current_thread")]
async fn builder_with_max_failover_attempts_threads_through() {
    let (ps, kv) = pubsub();
    let dispatcher = A2aDispatcher::builder()
        .handler(handler())
        .authenticator(auth())
        .pubsub(ps)
        .with_leader_election(kv)
        .with_max_failover_attempts(7)
        .build()
        .expect("test builder");
    assert_eq!(dispatcher.max_failover_attempts(), 7);
}

#[tokio::test(flavor = "current_thread")]
async fn builder_with_kv_reaper_threads_through() {
    let (ps, kv) = pubsub();
    let dispatcher = A2aDispatcher::builder()
        .handler(handler())
        .authenticator(auth())
        .pubsub(ps)
        .with_leader_election(kv)
        .with_kv_reaper(Duration::from_millis(250))
        .build()
        .expect("test builder");
    assert_eq!(
        dispatcher.kv_reaper_interval(),
        Some(Duration::from_millis(250)),
    );
}

#[tokio::test(flavor = "current_thread")]
async fn defaults_unchanged_when_builder_methods_not_called() {
    let (ps, _kv) = pubsub();
    let dispatcher = A2aDispatcher::builder()
        .handler(handler())
        .authenticator(auth())
        .pubsub(ps)
        .build()
        .expect("test builder");
    assert_eq!(dispatcher.leader_ttl(), LEADER_TTL);
    assert_eq!(dispatcher.leader_heartbeat_interval(), LEADER_TTL / 2);
    assert_eq!(dispatcher.max_failover_attempts(), FAILOVER_ATTEMPT_CAP);
    assert!(dispatcher.kv_reaper_interval().is_none());
}

#[tokio::test(flavor = "current_thread")]
async fn new_shortcut_uses_defaults() {
    let (ps, _kv) = pubsub();
    let dispatcher = A2aDispatcher::new(handler(), auth(), ps);
    assert_eq!(dispatcher.leader_ttl(), LEADER_TTL);
    assert_eq!(dispatcher.leader_heartbeat_interval(), LEADER_TTL / 2);
    assert_eq!(dispatcher.max_failover_attempts(), FAILOVER_ATTEMPT_CAP);
    assert!(dispatcher.kv_reaper_interval().is_none());
}
