#![cfg(not(target_arch = "wasm32"))]
//! Strict Lean-value conformance rejection tests.

use assert_matches::assert_matches;
use std::collections::BTreeMap;
use telltale_machine::coroutine::{Fault, Value};
use telltale_machine::instr::{ImmValue, Instr};
use telltale_machine::runtime::loader::CodeImage;
use telltale_machine::{ProtocolMachine, ProtocolMachineConfig, ProtocolMachineError};
use telltale_types::{GlobalType, Label, LocalTypeR};

#[allow(dead_code, unreachable_pub)]
#[path = "support/mod.rs"]
mod test_support;

use test_support::PassthroughHandler;

#[test]
fn choose_rejects_non_string_label_payload() {
    let mut local_types = BTreeMap::new();
    local_types.insert(
        "A".to_string(),
        LocalTypeR::send_choice(
            "B",
            vec![
                (Label::new("yes"), None, LocalTypeR::End),
                (Label::new("no"), None, LocalTypeR::End),
            ],
        ),
    );
    local_types.insert(
        "B".to_string(),
        LocalTypeR::recv_choice(
            "A",
            vec![
                (Label::new("yes"), None, LocalTypeR::End),
                (Label::new("no"), None, LocalTypeR::End),
            ],
        ),
    );

    let image = CodeImage {
        programs: {
            let mut m = BTreeMap::new();
            m.insert("A".to_string(), vec![Instr::Halt]);
            m.insert(
                "B".to_string(),
                vec![
                    Instr::Choose {
                        chan: 0,
                        table: vec![("yes".into(), 1), ("no".into(), 1)],
                    },
                    Instr::Halt,
                ],
            );
            m
        },
        global_type: GlobalType::comm(
            "A",
            "B",
            vec![
                (Label::new("yes"), GlobalType::End),
                (Label::new("no"), GlobalType::End),
            ],
        ),
        local_types,
    };

    let mut machine = ProtocolMachine::new(ProtocolMachineConfig::default());
    let sid = machine
        .load_choreography(&image)
        .expect("load choreography");
    machine
        .sessions_mut()
        .get_mut(sid)
        .expect("session")
        .send("A", "B", Value::Nat(1))
        .expect("inject malformed payload");
    machine.pause_role("A");

    let handler = PassthroughHandler;
    let result = machine.run(&handler, 16);
    assert_matches!(
        result,
        Err(ProtocolMachineError::Fault {
            fault: Fault::TypeViolation { .. },
            ..
        })
    );
}

#[test]
fn tag_rejects_non_fact_shape() {
    let image = CodeImage {
        programs: {
            let mut m = BTreeMap::new();
            m.insert(
                "A".to_string(),
                vec![
                    Instr::Set {
                        dst: 1,
                        val: ImmValue::Str("not-a-fact".to_string()),
                    },
                    Instr::Tag { fact: 1, dst: 2 },
                    Instr::Halt,
                ],
            );
            m
        },
        global_type: GlobalType::End,
        local_types: {
            let mut m = BTreeMap::new();
            m.insert("A".to_string(), LocalTypeR::End);
            m
        },
    };

    let mut machine = ProtocolMachine::new(ProtocolMachineConfig::default());
    machine
        .load_choreography(&image)
        .expect("load choreography");

    let handler = PassthroughHandler;
    let result = machine.run(&handler, 8);
    assert_matches!(
        result,
        Err(ProtocolMachineError::Fault {
            fault: Fault::Transfer { .. },
            ..
        })
    );
}
