"""
Exercise 2: profile, then cache (medium)

STEP 1: hottest_function(fn) runs fn() under cProfile and returns the NAME of the function (from this
        module, i.e. whose filename is __file__) with the largest tottime. Use pstats.Stats(profile).stats:
        keys are (filename, lineno, funcname), values are (cc, nc, tottime, cumtime, callers).
STEP 2: route_cost(a, b) is a pure but slow function (it sleeps 0.01 s). Make cached_total(pairs) fast by
        caching route_cost with functools.lru_cache (maxsize=1024) so repeated pairs aren't recomputed.
        Expose the cached function as `cached_route_cost` (so the check can inspect cache_info()).
"""

import cProfile
import functools
import pstats
import time


def hottest_function(fn):
    fn()
    return ""  # TODO


def route_cost(a, b):
    time.sleep(0.01)
    return abs(a - b) * 3


cached_route_cost = route_cost  # TODO: lru_cache


def cached_total(pairs):
    return sum(cached_route_cost(a, b) for a, b in pairs)


# --- self-check: do not modify below this line ---
def parse_rows():
    return [str(i) * 3 for i in range(2000)]


def slow_validation():
    total = 0
    for _ in range(300):
        for j in range(1000):
            total += j % 7
    return total


def report():
    parse_rows()
    slow_validation()

checks = []
checks.append(("finds the hotspot", hottest_function(report), "slow_validation"))
pairs = [(i % 5, (i * 3) % 5) for i in range(200)]
start = time.perf_counter()
total = cached_total(pairs)
elapsed = time.perf_counter() - start
checks.append(("total correct", total, sum(abs(a - b) * 3 for a, b in pairs)))
checks.append(("cached (< 0.5 s for 200 calls)", elapsed < 0.5, True))
checks.append(("cache used", getattr(cached_route_cost, "cache_info", lambda: None)() is not None and cached_route_cost.cache_info().hits > 150, True))

passed = 0
for label, actual, expected in checks:
    ok = actual == expected
    passed += ok
    print(f"{'PASS' if ok else 'FAIL'}: {label} (got {actual!r}, expected {expected!r})")

print("PASS" if passed == len(checks) else "FAIL")
