```typescript
export function applyCharges(caps: Record<string, [number, number]>, charges: [string, string, number][]): { left: Record<string, number>; refused: [string, string][] } {
  const result: { left: Record<string, number>; refused: [string, string][] } = {
    left: {},
    refused: []
  };

  for (const [id, bucketName, amount] of charges) {
    if (typeof amount !== 'number' || amount <= 0 || !Number.isInteger(amount)) {
      throw new Error('Amount must be a positive whole number');
    }

    const cap = caps[bucketName];
    if (!cap) {
      result.refused.push([id, 'unknown']);
      continue;
    }

    const [totalAllowance, maxSingleCharge] = cap;
    if (amount > maxSingleCharge) {
      result.refused.push([id, 'single']);
      continue;
    }

    if (result.left[bucketName] === undefined) {
      result.left[bucketName] = totalAllowance - amount;
      if (result.left[bucketName] < 0) {
        result.refused.push([id, 'cap']);
        result.left[bucketName] = totalAllowance; // Revert the charge
      }
    } else {
      const remainingAllowance = result.left[bucketName];
      if (remainingAllowance >= amount) {
        result.left[bucketName] -= amount;
      } else {
        result.refused.push([id, 'cap']);
      }
    }
  }

  return result;
}
```