"""add_policy.py: your turn, add one more reliability pattern: the circuit breaker.

retry handles a call that fails a few times. But if a service is fully down, retrying every single
request just wastes time and money. A CIRCUIT BREAKER fixes this: after N failures in a row it
"opens" and fails fast (no call at all) for a cooldown, then "half-opens" to test one request.

Steps:
  1. Finish CircuitBreaker.call below so it: counts consecutive failures, opens after `threshold`,
     fails fast while open, and resets on a success.
  2. Try it with a function that always raises and watch it stop calling after the threshold.
  3. Run:  python add_policy.py

Worked patterns (retry, timeout, fallback, step cap, approval gate) are in ../solution/reliability.py.
"""

import sys, os
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "solution"))
from reliability import TransientError


class CircuitBreaker:
    def __init__(self, threshold=3):
        self.threshold = threshold
        self.failures = 0
        self.open = False

    def call(self, fn):
        # TODO: if self.open, fail fast (raise TransientError("circuit open")) without calling fn.
        # TODO: try fn(); on success reset self.failures to 0 and return the result.
        # TODO: on failure, increment self.failures; if it reaches threshold, set self.open = True; re-raise.
        raise NotImplementedError("implement the circuit breaker")


if __name__ == "__main__":
    cb = CircuitBreaker(threshold=3)
    calls = {"n": 0}
    def always_down():
        calls["n"] += 1
        raise TransientError("down")
    for i in range(6):
        try:
            cb.call(always_down)
        except TransientError as e:
            print(f"attempt {i+1}: {e}  (open={cb.open})")
    # Goal: after 3 real failures the breaker opens and stops calling, so calls['n'] stays at 3.
    print("actual calls made:", calls["n"], "(should stop at the threshold once open)")
