```python
from typing import Dict, List, Tuple, Optional

def _why_refused(cap: Optional[Tuple[int, int]], left: int, amount: int) -> str:
    if cap is None:
        return "unknown"
    if amount > cap[1]:
        return "single"
    return "cap" if amount > left else ""

def apply_charges(caps: Dict[str, Tuple[int, int]], charges: List[Tuple[int, str, int]]) -> Dict[str, Dict[str, int]]:
    left = {name: cap[0] for name, cap in caps.items()}
    refused = []
    
    for charge_id, bucket, amount in charges:
        if bucket not in left:
            refused.append((charge_id, "unknown"))
            continue
        
        if amount <= 0:
            raise ValueError("Amount must be a positive whole number")
        
        if amount > left[bucket]:
            refused.append((charge_id, "cap"))
            continue
        
        left[bucket] -= amount
    
    return {"left": left, "refused": refused}
```