import datetime
from sqlalchemy.sql.expression import func, desc

from pyramid.view import view_config

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

from brewman.models.voucher import Voucher, Journal, VoucherType
from brewman.views.reports.closing_stock import get_opening_stock, get_closing_stock
from brewman.views.services.session import session_period_start, session_period_finish


@view_config(request_method='GET', route_name='profit_loss', renderer='brewman:templates/angular_base.mako',
             permission='Profit & Loss')
def html(request):
    return {}


@view_config(request_method='GET', route_name='api_profit_loss', renderer='json', permission='Profit & Loss')
def get_profit_loss(request):
    start_date = request.GET.get('StartDate', None)
    finish_date = request.GET.get('FinishDate', None)
    if start_date and finish_date:
        report = {'StartDate': start_date, 'FinishDate': finish_date}
        start_date = datetime.datetime.strptime(start_date, '%d-%b-%Y')
        finish_date = datetime.datetime.strptime(finish_date, '%d-%b-%Y')
        report['Body'], report['Footer'] = build_profit_loss(start_date, finish_date)
        return report
    else:
        return {'StartDate': session_period_start(request),
                'FinishDate': session_period_finish(request), 'Body': [], 'Footer': {}}


def build_profit_loss(start_date, finish_date):
    profit_type_list = [i.id for i in LedgerType.list() if i.balance_sheet == False]
    report = []
    groups = dict()

    amount_sum = func.sum(Journal.amount * Journal.debit)
    query = DBSession.query(LedgerBase, amount_sum) \
        .join(Journal.voucher).join(Journal.ledger) \
        .filter(Voucher.date >= start_date) \
        .filter(Voucher.date <= finish_date) \
        .filter(Voucher.type != VoucherType.by_name('Issue').id) \
        .filter(LedgerBase.type.in_(profit_type_list)) \
        .group_by(LedgerBase).order_by(LedgerBase.type).order_by(desc(func.abs(amount_sum))).all()

    # Get opening / closing stock
    opening_stock = get_opening_stock(start_date)
    closing_stock = get_closing_stock(finish_date)
    total_amount = (opening_stock - closing_stock) * -1

    report.append({'Name': 'Opening Stock', 'SubAmount': opening_stock * -1, 'Order': 20.0001})
    report.append({'Name': 'Closing Stock', 'SubAmount': closing_stock, 'Order': 29})
    purchase_group = LedgerType.by_id(2)
    groups[purchase_group.id] = {'Group': purchase_group.name, 'Amount': total_amount, 'Order': purchase_group.order}

    counter = 0
    for ledger, amount in query:
        # Add Items
        amount *= -1
        ledger_type = LedgerType.by_id(ledger.type)
        total_amount += amount

        if amount != 0:
            counter += .001
            report.append({'Name': ledger.name, 'SubAmount': amount, 'Order': ledger_type.order + counter})
            if ledger_type.id in groups:
                groups[ledger_type.id]['Amount'] += amount
            else:
                groups[ledger_type.id] = {'Group': ledger_type.name, 'Amount': amount, 'Order': ledger_type.order}

    # Add Subtotals
    for item in groups.values():
        report.append(item)

    footer = []
    # Add Net
    if total_amount > 0:
        footer.append({'Group': 'Net Profit', 'Amount': total_amount, 'Order': 100})
    else:
        footer.append({'Group': 'Net Loss', 'Amount': total_amount, 'Order': 100})

    return sorted(report, key=lambda d: d['Order']), footer


def get_accumulated_profit(finish_date):
    type_list = [i.id for i in LedgerType.list() if i.balance_sheet == False]

    accumulated_profit = DBSession.query(func.sum(Journal.amount * Journal.debit))\
    .join(Journal.voucher).join(Journal.ledger)\
    .filter(Voucher.date <= finish_date)\
    .filter(Voucher.type != VoucherType.by_name('Issue').id)\
    .filter(LedgerBase.type.in_(type_list))\
    .scalar()
    return 0 if accumulated_profit is None else accumulated_profit

