from pyramid.security import authenticated_userid
from pyramid.view import view_config
from sqlalchemy import func
from brewman import groupfinder
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_finish, session_period_start, session_current_date


@view_config(route_name='dashboard', renderer='brewman:templates/angular_base.mako', permission='Authenticated')
def html(request):
    return {}


@view_config(route_name='api_dashboard', renderer='json')
@TryCatchFunction
def dashboard(request):
    user = authenticated_userid(request)
    if user is None or 'Dashboard' not in groupfinder(user, request):
        return {'Enabled': False}
    start_date = request.GET.get('s', session_period_start(request))
    finish_date = request.GET.get('f', session_period_finish(request))
    dash = {'Enabled': True, 'StartDate': start_date, 'FinishDate': finish_date}
    if 'Cash Flow' in groupfinder(user, request):
        cash_details, cash_changes, cash_daily = get_ledger_type_info(1, start_date, finish_date)
        dash['Cash'] = {'Details': cash_details, 'Daily': cash_daily, 'Changes': cash_changes}
    if 'Balance Sheet' in groupfinder(user, request):
        creditors_details, creditors_changes, creditors_daily = get_ledger_type_info(9, start_date, finish_date)
        dash['Creditors'] = {'Details': creditors_details, 'Daily': creditors_daily, 'Changes': creditors_changes}
    if 'Profit & Loss' in groupfinder(user, request):
        sale_details, sale_changes, sale_daily = get_ledger_type_info(3, start_date, finish_date)
        dash['Sale'] = {'Details': sale_details, 'Daily': sale_daily, 'Changes': sale_changes}
    return dash


def get_sale(start_date, finish_date):
    SALE_LEDGER_TYPE = 3
    amount_sum = func.sum(Journal.amount * Journal.debit).label('sum')

    daily_sale = DBSession.query(Voucher.date, 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 == SALE_LEDGER_TYPE) \
        .group_by(Voucher.date).order_by(Voucher.date).all()

    total_sale = 0
    days = 0
    for date, sale in daily_sale:
        days += 1
        total_sale += sale
    return round(total_sale * -1, 2), round(total_sale / days * -1, 2), days


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

    details = []
    for ledger, amount in query:
        if round(amount, 2) != 0:
            details.append({'Name': ledger.name, 'Amount': round(amount, 2)})

    running = DBSession.query(amount_sum) \
        .join(Journal.voucher).join(Journal.ledger) \
        .filter(Voucher.date < start_date) \
        .filter(Voucher.type != VoucherType.by_name('Issue').id) \
        .filter(LedgerBase.type == ledger_type) \
        .scalar()

    running = 0 if running is None else round(running, 2)

    query = DBSession.query(Voucher.date, 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 == ledger_type) \
        .group_by(Voucher.date).order_by(Voucher.date).all()

    daily = []
    changes = []
    for date, amount in query:
        changes.append({'Date': date.strftime('%d-%b-%Y'), 'Amount': round(amount, 2)})
        running += round(amount, 2)
        daily.append({'Date': date.strftime('%d-%b-%Y'), 'Amount': round(running, 2)})
    return details, changes, daily
