"""
test_delay_chain.py - proves the delay arithmetic without VSI.

    python test_delay_chain.py

Each case prints PASS or FAIL with the numbers; exit status 1 on any FAIL.
A deliberately wrong expectation is included as a negative control so a broken
checker cannot report all green.
"""

import os
import sys

sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
from vsi_delay import VariableDelay, run_chain  # noqa: E402

failures = 0


def check(label, got, expected):
    global failures
    ok = got == expected
    print("{:<52} {}".format(label, "PASS" if ok else "FAIL"))
    if not ok:
        failures += 1
        print("    expected:", expected)
        print("    got     :", got)


# 1. single delay of 2: output lags input by two steps, zeros before
sent, got = run_chain([VariableDelay(2)], 6)
check("single delay 2", got, [0, 0, 1, 2, 3, 4])

# 2. two instances back to back, 2 + 3 = 5 steps
sent, got = run_chain([VariableDelay(2, name="delay1"), VariableDelay(3, name="delay2")], 10)
check("delay 2 then delay 3 = 5", got, [0, 0, 0, 0, 0, 1, 2, 3, 4, 5])

# 3. a zero-length delay is a pass-through and does not break the chain
sent, got = run_chain([VariableDelay(0), VariableDelay(1)], 4)
check("delay 0 then delay 1 = 1", got, [0, 1, 2, 3])

# 4. four instances: total is the sum
delays = [VariableDelay(1), VariableDelay(2), VariableDelay(0), VariableDelay(3)]
sent, got = run_chain(delays, 12)
check("four instances 1+2+0+3 = 6", got, [0] * 6 + [1, 2, 3, 4, 5, 6])

# 5. runtime change: 1 step, then after step 4 becomes 3 steps
d = VariableDelay(1, schedule={4: 3})
sent, got = run_chain([d], 10)
# steps 0..3 lag 1: 0,1,2,3 ; at step 4 the line lengthens to 3 (two initial zeros
# are prepended), so outputs 0,0,4,5,6,7 follow
check("schedule 1 -> 3 at step 4", got, [0, 1, 2, 3, 0, 0, 4, 5, 6, 7])

# 6. runtime shortening keeps the most recent samples
d = VariableDelay(3)
for v in (1, 2, 3):
    d.step(v)            # buffer now holds 1,2,3 ; next output would be 1
d.set_steps(1)          # keep only the newest sample
check("shorten 3 -> 1 keeps newest", d.step(4), 3)

# 7. configuration sources: env var beats json beats default
cfg = os.path.join(os.path.dirname(os.path.abspath(__file__)), "delay_config.json")
os.environ.pop("VSI_DELAY_DELAY1", None)
d1 = VariableDelay.from_config("delay1", default=9, config_path=cfg)
check("json config for delay1", d1.steps, 2)
os.environ["VSI_DELAY_DELAY1"] = "7"
d1 = VariableDelay.from_config("delay1", default=9, config_path=cfg)
check("env var overrides json", d1.steps, 7)
os.environ.pop("VSI_DELAY_DELAY1", None)
d9 = VariableDelay.from_config("nosuch", default=9, config_path=cfg)
check("default when unconfigured", d9.steps, 9)

# 8. negative control: a wrong expectation MUST fail
sent, got = run_chain([VariableDelay(2)], 4)
wrong = got == [1, 2, 3, 4]
print("{:<52} {}".format("negative control (must read FAIL)", "FAIL" if not wrong else "PASS"))
if wrong:
    failures += 1
    print("    the checker accepted a wrong expectation")

print()
print("{} failure(s) in the real cases".format(failures))
sys.exit(1 if failures else 0)
