import datetime
from sqlalchemy.orm.util import aliased
from sqlalchemy.sql.expression import func, desc

from pyramid.view import view_config

from brewman.models import DBSession
from brewman.models.master import LedgerBase, LedgerType

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

@view_config(request_method='GET', route_name='cash_flow', renderer='brewman:templates/angular_base.mako',
    permission='Cash Flow')
@view_config(request_method='GET', route_name='cash_flow_id', renderer='brewman:templates/angular_base.mako',
    permission='Cash Flow')
def get_html(request):
    return {}


@view_config(request_method='GET', route_name='api_cash_flow', renderer='json', permission='Cash Flow')
def get_cash_flow(request):
    start_date = request.GET.get('StartDate', None)
    finish_date = request.GET.get('FinishDate', None)
    if start_date and finish_date:
        return build_report(request, start_date, finish_date)
    else:
        return {'StartDate': session_period_start(request),
                'FinishDate': session_period_finish(request), 'Body': [], 'Footer': {}}


@view_config(request_method='GET', route_name='api_cash_flow_id', renderer='json', permission='Cash Flow')
def get_cash_flow_id(request):
    id = request.matchdict.get('id', None)
    start_date = request.GET.get('StartDate', None)
    finish_date = request.GET.get('FinishDate', None)
    return build_report_id(request, int(id), start_date, finish_date)


def build_report(request, start_date, finish_date):
    report = {'StartDate': start_date, 'FinishDate': finish_date, 'Body': [], 'Footer': []}
    sub_voucher = aliased(Voucher)
    sub_journal = aliased(Journal)
    sub_ledger = aliased(LedgerBase)

    sub_query = DBSession.query(sub_voucher.id)\
    .join(sub_journal, sub_voucher.journals)\
    .join(sub_ledger, sub_journal.ledger)\
    .filter(sub_ledger.type == LedgerType.by_name('Cash').id)\
    .filter(sub_voucher.date >= datetime.datetime.strptime(start_date, '%d-%b-%Y'))\
    .filter(sub_voucher.date <= datetime.datetime.strptime(finish_date, '%d-%b-%Y')).subquery()

    query = DBSession.query(LedgerBase.type, func.sum(Journal.signed_amount))\
    .join(Journal, Voucher.journals)\
    .join(LedgerBase, Journal.ledger)\
    .filter(Voucher.id.in_(sub_query))\
    .filter(LedgerBase.type != LedgerType.by_name('Cash').id)\
    .group_by(LedgerBase.type)\
    .order_by(func.sum(Journal.signed_amount)).all()

    total_inflow = 0
    total_outflow = 0
    for ledgerType, amount in query:
        lt = LedgerType.by_id(ledgerType)
        inflow = amount * -1 if amount < 0 else 0
        outflow = amount if amount >= 0 else 0
        total_inflow += (amount * -1) if amount < 0 else 0
        total_outflow += amount if amount >= 0 else 0
        report['Body'].append({'Name': lt.name, 'Url': request.route_url('cash_flow_id', id=str(lt.id),
            _query={'StartDate': start_date, 'FinishDate': finish_date}), 'Inflow': inflow, 'Outflow': outflow})

    report['Footer'].append({'Name': 'Total', 'Inflow': total_inflow, 'Outflow': total_outflow})

    net_inflow = total_inflow - total_outflow
    report['Footer'].append({'Name': 'Net', 'Inflow': (net_inflow if net_inflow >= 0 else 0),
                             'Outflow': (net_inflow * -1 if net_inflow < 0 else 0)})
    return report


def build_report_id(request, ledger_type, start_date, finish_date):
    report = {'StartDate': start_date, 'FinishDate': finish_date, 'Body': [], 'Footer': []}
    sub_voucher = aliased(Voucher)
    sub_journal = aliased(Journal)
    sub_ledger = aliased(LedgerBase)

    sub_query = DBSession.query(sub_voucher.id)\
    .join(sub_journal, sub_voucher.journals)\
    .join(sub_ledger, sub_journal.ledger)\
    .filter(sub_ledger.type == LedgerType.by_name('Cash').id)\
    .filter(sub_voucher.date >= datetime.datetime.strptime(start_date, '%d-%b-%Y'))\
    .filter(sub_voucher.date <= datetime.datetime.strptime(finish_date, '%d-%b-%Y')).subquery()

    query = DBSession.query(LedgerBase, func.sum(Journal.signed_amount))\
    .join(Journal, Voucher.journals)\
    .join(LedgerBase, Journal.ledger)\
    .filter(Voucher.id.in_(sub_query))\
    .filter(LedgerBase.type == ledger_type)\
    .group_by(LedgerBase)\
    .order_by(desc(func.sum(Journal.amount))).all()

    totalInflow = 0
    totalOutflow = 0
    for ledger, amount in query:
        inflow = amount * -1 if amount < 0 else 0
        outflow = amount if amount >= 0 else 0
        totalInflow += (amount * -1) if amount < 0 else 0
        totalOutflow += amount if amount >= 0 else 0
        report['Body'].append({'Name': ledger.name, 'Url': request.route_url('ledger_id', id=ledger.id,
            _query={'StartDate': start_date, 'FinishDate': finish_date}), 'Inflow': inflow, 'Outflow': outflow})

    report['Footer'].append({'Name': 'Total', 'Inflow': totalInflow, 'Outflow': totalOutflow})
    return report
