"""
Exercise 2: parse a requirements file and detect conflicts (medium)

Implement parse_requirements(text) -> dict mapping a NORMALIZED package name to a list of specifier strings:
  - Ignore blank lines and comments (anything after '#').
  - Ignore options lines starting with '-' (e.g. "-r base.txt", "--hash=...").
  - Drop environment markers (anything after ';') and extras ("requests[socks]" -> "requests").
  - Normalize names per PEP 503: lowercase, runs of '-', '_' and '.' become a single '-'.
  - A line with no specifier ("rich") gets "" in its list. The same package may appear several times;
    collect all its specifiers in order.
And find_conflicts(reqs, available) -> sorted list of package names for which NO version in
available[name] satisfies all collected specifiers combined (use satisfies() provided, joining with ",").
"""

import re


def satisfies(version, spec):
    def key(v):
        return tuple(int(p) for p in v.split("."))
    for clause in [c.strip() for c in spec.split(",") if c.strip()]:
        op = re.match(r"(==|!=|>=|<=|>|<)", clause).group(1)
        t = clause[len(op):].strip()
        a, b = key(version), key(t)
        ok = {"==": a == b, "!=": a != b, ">=": a >= b, "<=": a <= b, ">": a > b, "<": a < b}[op]
        if not ok:
            return False
    return True


def parse_requirements(text):
    return {}  # TODO


def find_conflicts(reqs, available):
    return []  # TODO


# --- self-check: do not modify below this line ---
text = """
# web stack
-r base.txt
FastAPI>=0.100,<1.0
requests[socks] >= 2.28 ; python_version >= "3.8"
Django_Rest.Framework==3.14.0   # pinned
rich
requests<2.30
urllib3>=2.1
urllib3<2.0   # conflicting pin from another team
--hash=sha256:abc
"""
reqs = parse_requirements(text)
checks = []
checks.append(("names normalized", sorted(reqs), ["django-rest-framework", "fastapi", "requests", "rich", "urllib3"]))
checks.append(("specifiers collected in order", reqs["requests"], [">= 2.28", "<2.30"]))
checks.append(("no specifier", reqs["rich"], [""]))
checks.append(("pinned", reqs["django-rest-framework"], ["==3.14.0"]))
available = {"fastapi": ["0.110.0", "1.0.0"], "requests": ["2.27.0", "2.29.0", "2.31.0"], "rich": ["13.7.0"],
             "django-rest-framework": ["3.14.0"], "urllib3": ["1.26.18", "2.2.1"]}
checks.append(("conflicts", find_conflicts(reqs, available), ["urllib3"]))

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")
