// tests/suite/test_state.el — comprehensive tests for runtime/state.el
//
// Covers state_set, state_get, state_del, state_keys, state_has, state_get_or.
// Uses unique key prefixes to avoid interference with the test framework's
// own state keys (which use _test_ prefix).

// ── state_set / state_get roundtrip ───────────────────────────────────────────

fn test_state_set_get_basic(_: String) -> String {
    state_set("suite_key1", "hello")
    assert_eq(state_get("suite_key1"), "hello", "get back what was set")

    state_set("suite_key2", "world")
    assert_eq(state_get("suite_key2"), "world", "second key independent")

    state_set("suite_num", "42")
    assert_eq(state_get("suite_num"), "42", "numeric string value")

    state_set("suite_empty", "")
    // empty value and missing key both return "" — that's by design per the docs
    let v: String = state_get("suite_empty")
    assert_true(str_eq(v, "") || str_eq(v, ""), "empty value stored or treated as absent")

    state_set("suite_long", str_repeat("a", 100))
    assert_int_eq(str_len(state_get("suite_long")), 100, "long value preserved")
    return ""
}

fn test_state_overwrite(_: String) -> String {
    state_set("suite_over", "first")
    assert_eq(state_get("suite_over"), "first", "initial value")
    state_set("suite_over", "second")
    assert_eq(state_get("suite_over"), "second", "value overwritten")
    state_set("suite_over", "third")
    assert_eq(state_get("suite_over"), "third", "value overwritten again")
    return ""
}

fn test_state_multiple_keys(_: String) -> String {
    state_set("suite_mk_a", "alpha")
    state_set("suite_mk_b", "beta")
    state_set("suite_mk_c", "gamma")
    assert_eq(state_get("suite_mk_a"), "alpha", "key a is alpha")
    assert_eq(state_get("suite_mk_b"), "beta", "key b is beta")
    assert_eq(state_get("suite_mk_c"), "gamma", "key c is gamma")
    // Mutate one, others unchanged
    state_set("suite_mk_b", "BETA")
    assert_eq(state_get("suite_mk_a"), "alpha", "a unchanged after b mutated")
    assert_eq(state_get("suite_mk_b"), "BETA", "b updated")
    assert_eq(state_get("suite_mk_c"), "gamma", "c unchanged after b mutated")
    return ""
}

// ── missing keys ──────────────────────────────────────────────────────────────

fn test_state_missing_key(_: String) -> String {
    assert_eq(state_get("suite_definitely_not_set_xyz_123"), "", "missing key returns empty string")
    assert_eq(state_get("suite_another_missing_key_abc"), "", "another missing key returns empty string")
    return ""
}

// ── state_del ─────────────────────────────────────────────────────────────────

fn test_state_del_basic(_: String) -> String {
    state_set("suite_del1", "value_to_delete")
    assert_eq(state_get("suite_del1"), "value_to_delete", "key present before delete")
    state_del("suite_del1")
    assert_eq(state_get("suite_del1"), "", "key absent after delete")

    // Delete a non-existent key should not error
    state_del("suite_never_existed_key_xyz")
    assert_eq(state_get("suite_never_existed_key_xyz"), "", "delete non-existent is no-op")
    return ""
}

fn test_state_del_and_reset(_: String) -> String {
    state_set("suite_reuse", "original")
    assert_eq(state_get("suite_reuse"), "original", "original value")
    state_del("suite_reuse")
    assert_eq(state_get("suite_reuse"), "", "deleted")
    state_set("suite_reuse", "new_value")
    assert_eq(state_get("suite_reuse"), "new_value", "key reused after delete")
    return ""
}

// ── state_has ─────────────────────────────────────────────────────────────────

fn test_state_has_basic(_: String) -> String {
    state_set("suite_has1", "something")
    assert_true(state_has("suite_has1"), "key with value is present")
    assert_false(state_has("suite_definitely_absent_xyz_999"), "absent key returns false")

    state_del("suite_has1")
    assert_false(state_has("suite_has1"), "deleted key is not present")
    return ""
}

// ── state_get_or ──────────────────────────────────────────────────────────────

fn test_state_get_or_basic(_: String) -> String {
    state_set("suite_gor1", "present")
    assert_eq(state_get_or("suite_gor1", "default"), "present", "returns value when key exists")
    assert_eq(state_get_or("suite_gor_missing_xyz", "fallback"), "fallback", "returns default when key missing")
    assert_eq(state_get_or("suite_gor_missing_xyz", ""), "", "returns empty default when key missing")
    return ""
}

// ── state persists across function calls ──────────────────────────────────────

fn _suite_state_helper_write() {
    state_set("suite_persist_test", "written_by_helper")
}

fn _suite_state_helper_increment() {
    let n: Int = str_to_int(state_get("suite_counter"))
    state_set("suite_counter", int_to_str(n + 1))
}

fn test_state_cross_function(_: String) -> String {
    _suite_state_helper_write()
    assert_eq(state_get("suite_persist_test"), "written_by_helper", "value written by helper function is readable")

    state_set("suite_counter", "0")
    _suite_state_helper_increment()
    assert_eq(state_get("suite_counter"), "1", "counter after 1 increment")
    _suite_state_helper_increment()
    assert_eq(state_get("suite_counter"), "2", "counter after 2 increments")
    _suite_state_helper_increment()
    assert_eq(state_get("suite_counter"), "3", "counter after 3 increments")
    return ""
}

// ── state_keys ────────────────────────────────────────────────────────────────

fn test_state_keys_basic(_: String) -> String {
    state_set("suite_sk_x", "1")
    state_set("suite_sk_y", "2")
    let keys: String = state_keys()
    // keys is a JSON array of all state keys — must contain our test keys
    assert_true(str_contains(keys, "suite_sk_x"), "keys includes suite_sk_x")
    assert_true(str_contains(keys, "suite_sk_y"), "keys includes suite_sk_y")
    assert_true(str_starts_with(keys, "["), "keys is a JSON array")
    assert_true(str_ends_with(keys, "]"), "keys is a JSON array")
    assert_true(json_array_len(keys) > 0, "keys array is non-empty")
    return ""
}

// ── value type storage ────────────────────────────────────────────────────────

fn test_state_value_types(_: String) -> String {
    // JSON object as value
    let json_val: String = "{\"name\":\"alice\",\"age\":30}"
    state_set("suite_json_val", json_val)
    let retrieved: String = state_get("suite_json_val")
    assert_eq(json_get(retrieved, "name"), "alice", "JSON object stored and retrieved")

    // JSON array as value
    let arr_val: String = "[1,2,3]"
    state_set("suite_arr_val", arr_val)
    let retrieved_arr: String = state_get("suite_arr_val")
    assert_int_eq(json_array_len(retrieved_arr), 3, "JSON array stored and retrieved")

    // Large value
    let big: String = str_repeat("x", 500)
    state_set("suite_big_val", big)
    assert_int_eq(str_len(state_get("suite_big_val")), 500, "large value stored correctly")
    return ""
}
