#!/usr/bin/env python2.7
# -*- Mode: Python -*-

#	$Id: paypal2ledger,v 1.7 2018/10/20 01:52:49 riastradh Exp $

import csv
import re
import sys

from datetime import datetime


def unirow(row):
    return tuple(unicode(x, 'utf-8') for x in row)

def paypal_to_iso8601(s):
    return datetime.strptime(s, '%m/%d/%Y').strftime('%Y-%m-%d')

def paypal_to_iso8601_short(s):
    return datetime.strptime(s, '%m/%d/%Y').strftime('%Y%m%d')

def negate(x):
    return x[1:] if x.startswith('-') else '-' + x


if len(sys.argv) != 3:
    p = sys.argv[0]
    if p.rfind('/') != -1:
        p = p[p.rfind('/') + 1:]
    sys.stderr.write('Usage: %s <account> <email>\n' % (sys.argv[0],))
    sys.exit(1)

base_acct = sys.argv[1]
email = sys.argv[2]

print '; -*- Mode: Ledger -*-'
print
print '; Stand back!  This file was generated automagically!'

bom = sys.stdin.read(3)
assert bom == b'\xef\xbb\xbf' or bom == b'\xbb\xbf\xef'
reader = csv.reader(sys.stdin)
header = unirow(next(reader))
curconv = None
last_txid = None
H = {h: i for i, h in enumerate(header)}
for posting in csv.reader(sys.stdin):
    P = lambda h: posting[H[h]]
    date = paypal_to_iso8601(P('Date'))
    sdate = paypal_to_iso8601_short(P('Date'))
    name = P('Name')
    from_email = P('From Email Address')
    to_email = P('To Email Address')
    txtype = P('Type')
    status = P('Status')
    txid = P('Transaction ID')
    reftxid = P('Reference Txn ID')
    currency = P('Currency')
    gross = P('Gross')
    fee = P('Fee')
    net = P('Net')
    balance = P('Balance')
    impact = P('Balance Impact')

    if curconv and txtype != 'General Currency Conversion':
        raise Exception('Unfinished currency conversion: %r' % (curconv,))
    if impact == 'Credit':
        assert to_email == email
    elif impact == 'Debit':
        assert from_email == email
    else:
        assert impact == 'Memo'
        continue

    if txtype == 'PayPal Here (KnuckleBuster) Payment' or \
       txtype == 'Donation Payment' or \
       txtype == 'General Payment' or \
       txtype == 'Mass Pay Payment' or \
       txtype == 'Mobile Payment' or \
       txtype == 'Subscription Payment' or \
       txtype == 'Website Payment':
        if impact == 'Debit':
            other_acct = 'Liabilities:PayPal:Payment:%s:%s' % (sdate, txid)
            other_email = to_email
            decl = True
        else:
            assert impact == 'Credit'
            other_acct = 'Income:Donations:PayPal'
            other_email = from_email
            decl = False
        print
        if decl:
            print 'account %s' % (other_acct,)
        print '%s %s <%s>' % (date, name, other_email)
        print '    Assets:%s:%s  %s %s = %s %s' % \
            (base_acct, currency, net, currency, balance, currency)
        print '    Expenses:Fees:%s  %s %s' % \
            (base_acct, negate(fee), currency)
        print '    %s  %s %s' % (other_acct, negate(gross), currency)
    elif txtype == 'PreApproved Payment Bill User Payment' or \
         txtype == 'General Withdrawal':
        assert impact == 'Debit'
        if txtype == 'PreApproved Payment Bill User Payment':
            subtype = 'Payment'
        elif txtype == 'General Withdrawal':
            subtype = 'Withdraw'
        else:
            assert False
        print
        print 'account Liabilities:%s:%s:%s:%s' % \
            (base_acct, subtype, sdate, txid)
        print '%s %s' % (date, name)
        print '    Liabilities:%s:%s:%s:%s  %s %s' % \
            (base_acct, subtype, sdate, txid, negate(gross), currency)
        print '    Expenses:Fees:%s  %s %s' % \
            (base_acct, negate(fee), currency)
        print '    Assets:%s:%s  %s %s = %s %s' % \
            (base_acct, currency, net, currency, balance, currency)
    elif txtype == 'Bank Deposit to PP Account (Obselete)' or \
         txtype == 'Bank Deposit to PP Account ':
        assert impact == 'Credit'
        print
        print 'account Assets:%s:Deposit:%s:%s' % (base_acct, sdate, txid)
        print '%s %s' % (date, name)
        print '    Assets:%s:%s  %s %s = %s %s' % \
            (base_acct, currency, net, currency, balance, currency)
        print '    Expenses:Fees:%s  %s %s' % \
            (base_acct, negate(fee), currency)
        print '    Assets:%s:Deposit:%s:%s  %s %s' % \
            (base_acct, sdate, txid, negate(gross), currency)
    elif txtype == 'General Currency Conversion':
        if curconv is None:
            assert reftxid == last_txid
            curconv = (txid, reftxid, net, gross, fee, balance, currency)
        else:
            cc_txid, cc_reftxid, cc_net, cc_gross, cc_fee, cc_bal, cc_cur = \
                curconv
            assert reftxid == cc_reftxid
            # print
            # print '%s Currency conversion' % (date,)
            print '    Assets:%s:%s  %s %s' % \
                (base_acct, currency, net, currency)
            print '    Expenses:Fees:%s  %s %s' % (base_acct, fee, currency)
            print '    Assets:%s:%s  %s %s' % \
                (base_acct, cc_cur, cc_net, cc_cur)
            print '    Expenses:Fees:%s  %s %s' % (base_acct, cc_fee, cc_cur)
            print
            print '%s Balance assertion' % (date,)
            print '    Assets:%s:%s  = %s %s' % \
                (base_acct, currency, balance, currency)
            print
            print '%s Balance assertion' % (date,)
            print '    Assets:%s:%s  = %s %s' % \
                (base_acct, cc_cur, cc_bal, cc_cur)
            curconv = None
    else:
        for h in header:
            print >>sys.stderr, '%s: %r' % (h, P(h))
        raise Exception('Unknown transaction type: %r' % (txtype,))

    last_txid = txid
