import datetime
import uuid
from sqlalchemy.sql.expression import func, case

from pyramid.view import view_config
from brewman.models import DBSession

from brewman.models.master import LedgerBase, CostCenter, Product, ProductGroup

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


@view_config(request_method='GET', route_name='raw_material_cost', renderer='brewman:templates/angular_base.mako',
             permission='Raw Material Cost')
@view_config(request_method='GET', route_name='raw_material_cost_id', renderer='brewman:templates/angular_base.mako',
             permission='Raw Material Cost')
def get_html(request):
    return {}


@view_config(request_method='GET', route_name='api_raw_material_cost', renderer='json', permission='Raw Material Cost')
def report_blank(request):
    return {'StartDate': session_period_start(request),
            'FinishDate': session_period_finish(request), 'Body': [], 'Footer': {}}


@view_config(request_method='GET', route_name='api_raw_material_cost', request_param='StartDate', renderer='json',
             permission='Raw Material Cost')
def report_data(request):
    start_date = request.GET.get('StartDate', None)
    finish_date = request.GET.get('FinishDate', None)
    return build_report(request, start_date, finish_date)


@view_config(request_method='GET', route_name='api_raw_material_cost_id', request_param='StartDate', renderer='json',
             permission='Raw Material Cost')
def report_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, uuid.UUID(id), start_date, finish_date)


def build_report(request, start_date, finish_date):
    report = {'StartDate': start_date, 'FinishDate': finish_date, 'Body': [], 'Footer': []}

    sum_issue = func.sum(case([(LedgerBase.type == 2, Journal.signed_amount)], else_=0)).label('Issue')
    sum_sale = (func.sum(case([(LedgerBase.type == 3, Journal.signed_amount)], else_=0)) * -1).label('Sale')

    query = DBSession.query(CostCenter, sum_issue, sum_sale) \
        .join(CostCenter.journals).join(Journal.voucher).join(Journal.ledger) \
        .filter(Voucher.date >= datetime.datetime.strptime(start_date, '%d-%b-%Y')) \
        .filter(Voucher.date <= datetime.datetime.strptime(finish_date, '%d-%b-%Y')) \
        .filter(Journal.cost_center_id != CostCenter.cost_center_purchase()) \
        .filter(LedgerBase.type.in_([2, 3])) \
        .group_by(CostCenter) \
        .order_by(sum_sale.desc()).all()

    issues = 0
    sales = 0
    for cost_center, issue, sale in query:
        issues += issue
        sales += sale
        rmc = 0 if sale == 0 else issue / sale
        report['Body'].append(
            {'Name': cost_center.name, 'Issue': issue, 'Sale': sale, 'Rmc': rmc,
             'Url': request.route_url('raw_material_cost_id', id=str(cost_center.id),
                                      _query={'StartDate': start_date, 'FinishDate': finish_date})})

    rmc = 0 if sales == 0 else issues / sales
    report['Footer'].append({'Name': 'Total', 'Issue': issues, 'Sale': sales, 'Rmc': rmc})

    return report


def build_report_id(request, cost_center_id, start_date, finish_date):
    report = {'StartDate': start_date, 'FinishDate': finish_date, 'Body': []}

    sum_quantity = func.sum(Inventory.quantity * Journal.debit).label('Quantity')
    sum_net = func.sum(Inventory.rate * Inventory.quantity * Journal.debit).label('Net')
    sum_gross = func.sum(Inventory.amount * Journal.debit).label('Gross')

    query = DBSession.query(Product, sum_quantity, sum_net, sum_gross) \
        .join(Product.inventories).join(Inventory.voucher).join(Voucher.journals).join(Product.product_group) \
        .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 == 3) \
        .filter(Journal.cost_center_id == cost_center_id) \
        .group_by(Product).group_by(Journal.debit).group_by(ProductGroup.name) \
        .order_by(ProductGroup.name).order_by(sum_net.desc()).all()

    groups = {}
    counter = 0
    list = []
    for product, quantity, net, gross in query:
        if product.product_group_id in groups:
            group = groups[product.product_group_id]
            group['Net'] += net
            group['Gross'] += gross
        else:
            counter += 500
            group = {'Group': product.product_group.name, 'Net': net, 'Gross': gross, 'Order': counter, 'Heading': True}
            groups[product.product_group_id] = group
        counter += 1
        list.append(
            {'Name': product.full_name, 'Group': product.product_group.name, 'Quantity': quantity, 'Net': net,
             'Gross': gross, 'Order': counter, 'Heading': False})

    for item in groups.values():
        list.append(item)

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