//! Multi-process: two FourEyesGate instances sharing a KvStore.
//! Submit on instance A wakes wait on instance B.

use ed25519_dalek::{Signer, SigningKey};
use klieo_bus_memory::MemoryBus;
use klieo_ops::approver_registry::{ApproverId, StaticApproverRegistry};
use klieo_ops::escalation::Severity;
use klieo_ops::gates::{ApprovalOutcome, FourEyesGate, Gate, GateDecision, GateRequest};
use std::collections::HashMap;
use std::sync::Arc;
use std::time::Duration;

#[tokio::test]
async fn submit_on_one_wakes_wait_on_another() {
    let bus = MemoryBus::new();
    let kv = bus.kv.clone();

    let alice_sk = SigningKey::from_bytes(&[1u8; 32]);
    let bob_sk = SigningKey::from_bytes(&[2u8; 32]);
    let mut keys = HashMap::new();
    keys.insert(ApproverId("alice".into()), alice_sk.verifying_key());
    keys.insert(ApproverId("bob".into()), bob_sk.verifying_key());
    let registry: Arc<dyn klieo_ops::approver_registry::ApproverRegistry> =
        Arc::new(StaticApproverRegistry::from_map(keys));

    // Instance A: evaluates + waits.
    let gate_a = Arc::new(
        FourEyesGate::new(
            kv.clone(),
            registry.clone(),
            2,
            FourEyesGate::dual_control_tools(&["payout"]),
        )
        .with_severity(Severity::High),
    );
    // Instance B: submits (simulates a separate process sharing the same KV).
    let gate_b = Arc::new(
        FourEyesGate::new(
            kv.clone(),
            registry,
            2,
            FourEyesGate::dual_control_tools(&["payout"]),
        )
        .with_severity(Severity::High),
    );

    let decision = gate_a
        .evaluate(GateRequest::new("payout", serde_json::json!({})))
        .await;
    let ticket = if let GateDecision::RequireApproval { ticket, .. } = decision {
        ticket
    } else {
        panic!("expected RequireApproval");
    };

    let gate_a_clone = gate_a.clone();
    let ticket_clone = ticket.clone();
    let waiter = tokio::spawn(async move {
        gate_a_clone
            .wait_for_approval(ticket_clone, Duration::from_secs(5))
            .await
    });

    // Submit from gate_b (different instance, same KV).
    tokio::time::sleep(Duration::from_millis(50)).await;
    let payload = b"multi-process";
    gate_b
        .submit_approval(
            &ticket,
            ApproverId("alice".into()),
            alice_sk.sign(payload),
            payload.to_vec(),
        )
        .expect("submit alice");
    gate_b
        .submit_approval(
            &ticket,
            ApproverId("bob".into()),
            bob_sk.sign(payload),
            payload.to_vec(),
        )
        .expect("submit bob");

    let outcome = waiter.await.unwrap().expect("wait ok");
    assert!(matches!(outcome, ApprovalOutcome::Allow));
}
