===== ISTEM =====
Solve the following programming task.

TASK: Payment and Refund Reconciliation

Write a function 'reconcile(transactions)' that processes a list of payment and refund transactions in order and returns a dict with two keys, 'balances' and 'rejected'.

Each transaction is a dict with the keys 'id' (str), 'type' ('payment' or 'refund'), 'account' (str) and 'amount' (int, in cents). A refund also has 'refers_to', the id of the payment it refunds. You can assume every transaction has these keys with these types.

Process the transactions in list order:
- A transaction whose id has already appeared earlier in the list is rejected with reason 'duplicate', whether or not the earlier one was accepted.
- A transaction whose amount is 0 or negative is rejected with reason 'invalid_amount'.
- A refund is rejected with reason 'unknown_payment' if 'refers_to' is not the id of an earlier, accepted payment. This includes ids of refunds, ids of rejected payments, and ids of payments that appear later in the list.
- A refund is rejected with reason 'account_mismatch' if its account differs from the account of the payment it refers to.
- A refund is rejected with reason 'over_refund' if the accepted refunds for that payment, including this one, would add up to more than the payment's amount.
- If more than one reason applies, use the first one in the order listed above.
- An accepted payment adds its amount to its account's balance; an accepted refund subtracts its amount. Rejected transactions change nothing.

Return:
- 'balances': a dict mapping each account that appears in at least one accepted transaction to its final balance in cents. Accounts that appear only in rejected transactions are not included.
- 'rejected': a list of (id, reason) tuples, in the order the rejected transactions appeared.

STARTER CODE (python):
def reconcile(transactions: list) -> dict:
    # Write your code here
    pass


RULES:
- Keep the function name and signature EXACTLY as given.
- Return working code only. No explanations.
- Put the code in a single ``` block.
- Try to solve it first. If you genuinely cannot, write only this single
  line instead of producing faulty code: CANNOT_SOLVE

===== HAM YANIT =====
```python
def reconcile(transactions: list) -> dict:
    seen_ids = set()
    accepted_payments = {}  # id -> {'account': str, 'amount': int, 'refunded': int}
    balances = {}
    rejected = []

    for txn in transactions:
        tid = txn['id']
        ttype = txn['type']
        account = txn['account']
        amount = txn['amount']

        # Check duplicate
        if tid in seen_ids:
            rejected.append((tid, 'duplicate'))
            continue

        # Check invalid amount
        if amount <= 0:
            rejected.append((tid, 'invalid_amount'))
            continue

        # Mark as seen after passing duplicate check (since we need to reject duplicates even if later ones pass other checks)
        # But we need to decide whether to add to seen_ids or not. 
        # The rule says: "A transaction whose id has already appeared earlier in the list is rejected with reason 'duplicate', whether or not the earlier one was accepted."
        # So we check if tid is in seen_ids. Then, regardless of whether this transaction is accepted or rejected for other reasons, we should add its id to seen_ids so that future duplicates are caught.
        # But wait: if the amount is invalid, we still want to mark the id as seen so that a later transaction with the same id gets 'duplicate'.
        # Let me re-read: "whether or not the earlier one was accepted" - so the earlier one could be rejected for invalid_amount, and a later one with same id should get 'duplicate'.
        # So we should add to seen_ids before checking other conditions? No, we need to add it after we've processed it (accepted or rejected for non-duplicate reasons).
        # Actually, let's think: if txn1 has id "a" and amount 0 (invalid), then txn2 has id "a" and amount 100 (payment). txn2 should be rejected as 'duplicate' because id "a" has already appeared.
        # So we need to add the id to seen_ids regardless of whether the transaction is accepted or rejected (as long as it's not itself a duplicate).
        
        seen_ids.add(tid)

        if ttype == 'payment':
            # Accept the payment
            accepted_payments[tid] = {
                'account': account,
                'amount': amount,
                'refunded': 0
            }
            if account in balances:
                balances[account] += amount
            else:
                balances[account] = amount
        else:  # refund
            refers_to = txn.get('refers_to')
            # Check if refers_to is an earlier accepted payment
            if refers_to not in accepted_payments:
                rejected.append((tid, 'unknown_payment'))
                continue
            
            payment_info = accepted_payments[refers_to]
            
            # Check account mismatch
            if account != payment_info['account']:
                rejected.append((tid, 'account_mismatch'))
                continue
            
            # Check over_refund
            if payment_info['refunded'] + amount > payment_info['amount']:
                rejected.append((tid, 'over_refund'))
                continue
            
            # Accept the refund
            payment_info['refunded'] += amount
            if account in balances:
                balances[account] -= amount
            else:
                balances[account] = -amount

    return {
        'balances': balances,
        'rejected': rejected
    }
```