from itertools import groupby as _groupby

from django.contrib.auth.decorators import login_required
from django.http import HttpResponse, Http404
from django.shortcuts import get_object_or_404
from django.template import RequestContext, loader

from go.billing import settings
from go.billing.models import Statement


def groupby(values, fn):
    return sorted([(k, list(g)) for k, g in _groupby(values, fn)])


def ensure_int(v):
    return v if v is not None else 0


def totals_from_items(items):
    return {
        'cost': sum(ensure_int(item.cost) for item in items),
        'credits': sum(ensure_int(item.credits) for item in items),
    }


def sections_from_items(all_items):
    all_items = sorted(all_items, key=lambda d: d.channel)
    sections = groupby(all_items, lambda line: line.channel)

    sections = [{
        'name': name,
        'totals': totals_from_items(items),
        'items': list(sorted(items, key=lambda d: d.description)),
    } for name, items in sections]

    return sections


def billers_from_items(all_items):
    billers = [{
        'name': name,
        'channel_type': items[0].channel_type,
        'sections': sections_from_items(items)
    } for name, items in groupby(all_items, lambda d: d.billed_by)]

    system_biller = next(
        (b for b in billers if b['name'] == settings.SYSTEM_BILLER_NAME),
        None)

    if system_biller is not None:
        billers.remove(system_biller)
        billers.append(system_biller)

    return billers


@login_required
def statement_view(request, statement_id=None):
    statement = get_object_or_404(Statement, pk=statement_id)
    items = list(statement.lineitem_set.all())

    if not (request.user.is_staff or
            statement.account.user == request.user):
        raise Http404

    template = loader.get_template('billing/invoice.html')

    context = RequestContext(request, {
        'statement': statement,
        'totals': totals_from_items(items),
        'billers': billers_from_items(items),
        'contact_details': settings.STATEMENT_CONTACT_DETAILS,
    })

    html_result = template.render(context)
    return HttpResponse(html_result)
