import datetime
from sqlalchemy.orm import joinedload_all
from sqlalchemy.sql.expression import func
import uuid

from pyramid.view import view_config
import transaction

from brewman.models import DBSession
from brewman.models.master import LedgerBase
from brewman.models.validation_exception import TryCatchFunction

from brewman.models.voucher import Voucher, Journal, VoucherType
from brewman.views.services.session import session_period_start, session_period_finish
from brewman.views.services.voucher import get_edit_url


@view_config(request_method='GET', route_name='reconcile_id', renderer='brewman:templates/angular_base.mako',
             permission='Reconcile')
@view_config(request_method='GET', route_name='reconcile', renderer='brewman:templates/angular_base.mako',
             permission='Reconcile')
def html(request):
    return {}


@view_config(request_method='GET', route_name='api_reconcile', renderer='json', permission='Reconcile')
def show_blank(request):
    return {'StartDate': session_period_start(request),
            'FinishDate': session_period_finish(request), 'Ledger': None, 'Body': [], 'Footer': {}}


@view_config(request_method='GET', route_name='api_reconcile_id', renderer='json', permission='Reconcile')
@TryCatchFunction
def show_data(request):
    id = request.matchdict['id']
    account = LedgerBase.by_id(uuid.UUID(id))
    start_date = request.GET.get('StartDate', session_period_start(request))
    finish_date = request.GET.get('FinishDate', session_period_finish(request))
    info = {'StartDate': start_date, 'FinishDate': finish_date,
            'Account': {'LedgerID': account.id, 'Name': account.name},
            'Body': [], 'Footer': {}}
    build_report(request, info)
    return info


def build_report(request, info):
    ledger_id = info['Account']['LedgerID']
    start_date = info['StartDate']
    finish_date = info['FinishDate']
    total_debit, total_credit, running_total, opening = opening_balance(ledger_id, start_date)
    info['Body'].append(opening)

    query = Voucher.query().options(joinedload_all(Voucher.journals, Journal.ledger, innerjoin=True)) \
        .filter(Voucher.journals.any(Journal.ledger_id == ledger_id)) \
        .filter(Voucher.date >= datetime.datetime.strptime(start_date, '%d-%b-%Y')) \
        .filter(Voucher.date <= datetime.datetime.strptime(finish_date, '%d-%b-%Y')) \
        .filter(Voucher.type != VoucherType.by_name('Issue').id) \
        .order_by(Voucher.reconcile_date).order_by(Voucher.last_edit_date).all()

    for voucher in query:
        debit = 0
        credit = 0
        journal_debit = 0
        name = ""
        for journal in voucher.journals:
            if journal.ledger_id == ledger_id:
                if voucher.posted:
                    running_total += (journal.amount * journal.debit)
                journal_debit = journal.debit
                if journal.debit == 1:
                    debit = journal.amount
                    total_debit += journal.amount
                    credit = ""
                else:
                    credit = journal.amount
                    total_credit += journal.amount
                    debit = ""
        for journal in voucher.journals:
            if journal.debit != journal_debit:
                name += "{0} / ".format(journal.ledger.name)
        name = name[:-3]
        info['Body'].append(
            {'VoucherID': voucher.id, 'Date': voucher.date.strftime('%d-%b-%Y'), 'Name': name,
             'Url': get_edit_url(request, voucher), 'Type': VoucherType.by_id(voucher.type).name,
             'Narration': voucher.narration, 'Debit': debit, 'Credit': credit, 'Running': running_total,
             'ReconcileDate': voucher.reconcile_date.strftime('%d-%b-%Y'), 'IsReconciled': voucher.is_reconciled})

    info['Footer'] = {'Date': finish_date, 'Name': 'Closing Balance', 'Type': 'Closing Balance',
                      'Narration': '', 'Debit': total_debit, 'Credit': total_credit,
                      'Running': running_total, 'Posted': True}


def opening_balance(ledgerID, start_date):
    opening = DBSession.query(func.sum(Journal.amount * Journal.debit)) \
        .join(Journal.voucher) \
        .filter(Voucher.date < datetime.datetime.strptime(start_date, '%d-%b-%Y')) \
        .filter(Voucher.type != VoucherType.by_name('Issue').id) \
        .filter(Journal.ledger_id == ledgerID) \
        .scalar()
    opening = 0 if opening is None else opening
    if opening < 0:
        credit = opening * -1
        debit = 0
    else:
        debit = opening
        credit = 0
    return 0, 0, opening, {'Date': start_date, 'Name': 'Opening Balance', 'Type': 'Opening Balance',
                           'Narration': '', 'Debit': debit, 'Credit': credit, 'Running': opening, 'Posted': True}


@view_config(request_method='POST', route_name='api_reconcile_id', renderer='json', permission='Reconcile')
def save(request):
    id = request.matchdict['id']
    account = LedgerBase.by_id(uuid.UUID(id))
    start_date = request.GET.get('StartDate', session_period_start(request))
    finish_date = request.GET.get('FinishDate', session_period_finish(request))
    for item in request.json_body['Body']:
        if 'VoucherID' not in item:
            continue
        voucher = Voucher.by_id(uuid.UUID(item['VoucherID']))
        is_reconciled = item['IsReconciled']
        reconcile_date = datetime.datetime.strptime(item['ReconcileDate'], '%d-%b-%Y')
        voucher.is_reconciled = is_reconciled
        voucher.reconcile_date = reconcile_date
    transaction.commit()

    info = {'StartDate': start_date, 'FinishDate': finish_date,
            'Account': {'LedgerID': account.id, 'Name': account.name},
            'Body': [], 'Footer': {}}
    build_report(request, info)
    return info

