#!/usr/bin/env python3
"""Illustrative tank, dimensioned in metres and seconds. No real plant model."""
DT, STEPS, AREA = 1.0, 80, 1.0
QOUT, QMAX, TARGET, GAIN = 0.01, 0.03, 1.0, 0.04


def simulate(kind):
    level, peak, stale_events, tripped = 1.0, 1.0, 0, False
    held_sample, held_time = 1.0, 0.0
    for step in range(STEPS):
        now = step * DT
        if kind == 'stale':
            measured, sample_time = held_sample, held_time
        else:
            measured = level - (0.25 if kind.startswith('bias') else 0.0)
            sample_time = now
        if now - sample_time > 5.0:
            stale_events += 1
        # Fresh timestamps do not make a biased sensor true.
        inflow = min(QMAX, max(0.0, QOUT + GAIN * (TARGET - measured)))
        # Demonstration only: hypothetical independent high-level protection.
        # Stops both flows and ends the simulation; not a universal safe action.
        if kind == 'bias+independent-trip' and level >= 1.20:
            tripped = True
            break
        level += (inflow - QOUT) * DT / AREA
        peak = max(peak, level)
    return level, peak, stale_events, tripped


def main():
    results = {}
    for kind in ('honest', 'stale', 'bias', 'bias+independent-trip'):
        level, peak, stale, trip = results[kind] = simulate(kind)
        print(f'{kind}: final={level:.3f}m peak={peak:.3f}m stale={stale} trip={trip}')
    assert results['honest'][0] == results['stale'][0] == 1.0
    assert results['stale'][2] == 74
    assert results['bias'][0] > 1.23 and results['bias'][2] == 0
    assert results['bias+independent-trip'][3]
    assert results['bias+independent-trip'][1] < results['bias'][1]


if __name__ == '__main__':
    main()
