"""Challenge 7: Validate an API Response
Check an API response (status code + JSON body):
  - status equals the expected status
  - body is a JSON object containing every required field with the right type
  - fields with expected values match (a list/set/tuple means "any of these")
Returns (is_valid, list_of_errors).
"""

import json


def validate_api_response(response, required_fields, expected_values=None,
                          expected_status=200):
    errors = []

    if response.get("status") != expected_status:
        errors.append(f"unexpected status: {response.get('status')}")

    # Body may arrive as a JSON string or an already-parsed dict
    body = response.get("body")
    if isinstance(body, str):
        try:
            body = json.loads(body)
        except json.JSONDecodeError:
            errors.append("body is not valid JSON")
            return False, errors
    if not isinstance(body, dict):
        errors.append("body missing or not a JSON object")
        return False, errors

    # Required fields and their types
    for field, ftype in required_fields.items():
        if field not in body:
            errors.append(f"missing field: {field}")
        elif not isinstance(body[field], ftype):
            errors.append(f"wrong type for {field}: expected {ftype.__name__}")

    # Expected values
    for field, expected in (expected_values or {}).items():
        if field not in body:
            continue  # already reported if it was required
        allowed = expected if isinstance(expected, (list, set, tuple)) else [expected]
        if body[field] not in allowed:
            errors.append(f"invalid value for {field}: {body[field]!r}")

    return (not errors), errors
    
    
    

if __name__ == "__main__":
    required = {"id": int, "name": str, "state": str}
    expected = {"state": ["active", "pending"]}

    good = {"status": 200, "body": {"id": 1, "name": "svc", "state": "active"}}
    bad_value = {"status": 200, "body": {"id": 1, "name": "svc", "state": "dead"}}
    missing = {"status": 200, "body": '{"id": 1}'}          # JSON string body
    bad_status = {"status": 500, "body": {"id": 1, "name": "x", "state": "active"}}
    no_body = {"status": 200}

    for label, resp in [("good", good), ("bad_value", bad_value), ("missing", missing),
                        ("bad_status", bad_status), ("no_body", no_body)]:
        print(label, validate_api_response(resp, required, expected))

    assert validate_api_response(good, required, expected)[0] is True
    assert validate_api_response(bad_value, required, expected)[0] is False
    assert len(validate_api_response(missing, required, expected)[1]) == 2
    assert validate_api_response(bad_status, required, expected)[0] is False
    assert validate_api_response(no_body, required, expected)[0] is False
    print("Challenge 7 OK")
