//! A2aTaskStore::put best-effort fanout contract.
//!
//! When the event sink's publish fails (bus down, encode failure,
//! invalid subject), put MUST return Ok(()) — the durable KV write
//! is the source of truth; the event publish is the best-effort
//! fanout layer per ADR-018. The publish failure must be logged
//! warn server-side (verified by absence of error propagation;
//! tracing-test wiring is out of scope for this test).

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

use async_trait::async_trait;
use bytes::Bytes;
use klieo_a2a::server::TaskEventSink;
use klieo_a2a::task_store::{A2aTaskStore, DEFAULT_BUCKET};
use klieo_a2a::types::{Task, TaskStatus};
use klieo_bus_memory::MemoryBus;
use klieo_core::{BusError, DurableName, Headers, MsgStream, Pubsub};
use std::sync::Arc;

struct FailingPubsub;

#[async_trait]
impl Pubsub for FailingPubsub {
    async fn publish(
        &self,
        _subject: &str,
        _payload: Bytes,
        _headers: Headers,
    ) -> Result<(), BusError> {
        Err(BusError::Connection("simulated".into()))
    }
    async fn subscribe(
        &self,
        _subject: &str,
        _durable: DurableName,
    ) -> Result<MsgStream, BusError> {
        Err(BusError::Connection("simulated".into()))
    }
}

#[tokio::test(flavor = "current_thread")]
async fn put_returns_ok_when_event_publish_fails() {
    let bus = MemoryBus::new();
    let failing: Arc<dyn Pubsub> = Arc::new(FailingPubsub);
    let sink = TaskEventSink::new(failing);
    let store = A2aTaskStore::new(bus.kv.clone(), DEFAULT_BUCKET.into()).with_event_sink(sink);

    let task = Task {
        id: "t-fail".into(),
        contextId: "ctx-fail".into(),
        status: TaskStatus::Submitted,
        artifacts: vec![],
        history: vec![],
        metadata: None,
    };

    // put must succeed even though the event sink will fail to publish.
    store.put(&task).await.unwrap();

    // KV write landed — task is retrievable.
    let got = store
        .get(&task.id)
        .await
        .unwrap()
        .expect("task missing from store");
    assert_eq!(got.id, "t-fail");
    assert!(matches!(got.status, TaskStatus::Submitted));
}
