# One dict that holds other dicts.
# nested dicts — structure, access, iteration, modification

# ─────────────────────────────────────────────
# Creating a nested dict
# ─────────────────────────────────────────────

roster = {
    "Raven": {"score": 85, "active": True},
    "Wolf":  {"score": 74, "active": False},
    "Ghost": {"score": 91, "active": True}
}

print(roster)
print(len(roster))      # 3 — number of outer keys

# ─────────────────────────────────────────────
# Accessing elements — outer key, then inner key
# ─────────────────────────────────────────────

print(roster["Raven"])              # {'score': 85, 'active': True}
print(roster["Raven"]["score"])     # 85
print(roster["Wolf"]["active"])     # False
print(roster["Ghost"]["score"])     # 91

# safe access with get()
print(roster.get("Viper", {}))                      # {} — outer key missing
print(roster["Raven"].get("rank", "unassigned"))    # unassigned — inner key missing

# ─────────────────────────────────────────────
# Looping — items() on outer, access inner directly
# ─────────────────────────────────────────────

for name, data in roster.items():
    print(f"{name}: score {data['score']}, active {data['active']}")

# Raven: score 85, active True
# Wolf: score 74, active False
# Ghost: score 91, active True

# loop and filter
for name, data in roster.items():
    if data["active"]:
        print(f"{name} is active")

# Raven is active
# Ghost is active

# ─────────────────────────────────────────────
# Modifying inner dicts
# ─────────────────────────────────────────────

roster["Wolf"]["active"] = True     # update inner key
roster["Raven"]["score"] = 99       # update inner value
roster["Ghost"]["rank"] = "Captain" # add new inner key

print(roster["Wolf"])               # {'score': 74, 'active': True}
print(roster["Raven"]["score"])     # 99
print(roster["Ghost"])              # {'score': 91, 'active': True, 'rank': 'Captain'}

# ─────────────────────────────────────────────
# Adding a new outer entry
# ─────────────────────────────────────────────

roster["Viper"] = {"score": 78, "active": True}
print(roster["Viper"])              # {'score': 78, 'active': True}
print(len(roster))                  # 4

# ─────────────────────────────────────────────
# Removing an entry
# ─────────────────────────────────────────────

removed = roster.pop("Wolf")
print(removed)                      # {'score': 74, 'active': True}
print(len(roster))                  # 3

# ─────────────────────────────────────────────
# Inner dicts don't need the same structure
# ─────────────────────────────────────────────

mixed = {
    "Raven": {"score": 85, "active": True, "rank": "Sergeant"},
    "Wolf":  {"score": 74},
    "Ghost": {"active": True}
}

for name, data in mixed.items():
    score = data.get("score", "no score")
    print(f"{name}: {score}")

# Raven: 85
# Wolf: 74
# Ghost: no score

# ─────────────────────────────────────────────
# Quick reference
# ─────────────────────────────────────────────

# {"key": {...}}            — nested dict literal
# d["outer"]["inner"]       — access inner value
# d.get("outer", {})        — safe outer access
# d["outer"].get("inner")   — safe inner access
#
# for name, data in d.items():   — loop outer
#     data["key"]                — access inner
#
# d["new_key"] = {...}      — add new outer entry
# d["outer"]["key"] = val   — add or update inner key
# d.pop("outer")            — remove outer entry
#
# inner dicts are full dicts — all methods work on them
# inner dicts don't need the same keys
