import json

__author__ = 'tanshu'

import uuid
from decimal import Decimal

from pyramid.security import authenticated_userid
import pkg_resources
from pyramid.response import Response, FileResponse
from pyramid.view import view_config
import transaction

from picard import groupfinder
from ..models import DBSession
from ..models.master import ProductGroup, Product
from ..models.validation_exception import ValidationError, TryCatchFunction


@view_config(route_name='product_group_list', permission='Authenticated')
@view_config(request_method='GET', route_name='product_group_id', permission='Product Groups')
@view_config(request_method='GET', route_name='product_group', permission='Product Groups')
def html(request):
    package, resource = 'picard:static/base.html'.split(':', 1)
    icon = pkg_resources.resource_filename(package, resource)
    return FileResponse(icon, request=request)


@view_config(request_method='POST', route_name='api_product_group', renderer='json', permission='Product Groups')
@TryCatchFunction
def save(request):
    name = request.json_body.get('Name', '').strip()
    if name == '':
        raise ValidationError('Validation', 'Name cannot be blank')
    max_discount = round(Decimal(request.json_body.get('MaxDiscount', 0)) / 100, 5)
    header = request.json_body.get('Header', '').strip()
    is_active = request.json_body.get('IsActive', True)
    sort_order = request.json_body.get('SortOrder', 0)
    item = ProductGroup(name, max_discount, header, sort_order, is_active)
    DBSession.add(item)
    transaction.commit()
    return product_group_info(item.id)


@view_config(request_method='POST', route_name='api_product_group_id', renderer='json', permission='Product Groups')
@TryCatchFunction
def update(request):
    item = ProductGroup.by_id(uuid.UUID(request.matchdict['id']))
    if item.is_fixture:
        raise ValidationError('Fixture', "{0} cannot be edited or deleted.".format(item.name))
    name = request.json_body.get('Name', '').strip()
    if name == '':
        raise ValidationError('Validation', 'Name cannot be blank')
    max_discount = round(Decimal(request.json_body.get('MaxDiscount', 0)) / 100, 5)
    header = request.json_body.get('Header', '').strip()
    is_active = request.json_body.get('IsActive', True)
    sort_order = request.json_body.get('SortOrder', 0)
    item.name = name
    item.max_discount = max_discount
    item.header = header
    item.sort_order = sort_order
    item.is_active = is_active
    transaction.commit()
    return product_group_info(item.id)


@view_config(request_method='DELETE', route_name='api_product_group_id', renderer='json', permission='Product Groups')
def delete(request):
    item = ProductGroup.by_id(uuid.UUID(request.matchdict['id']))
    can_delete, reason = item.can_delete('Advanced Delete' in groupfinder(authenticated_userid(request), request))

    if can_delete:
        delete_with_data(item)
        transaction.commit()
        return product_group_info(None)
    else:
        transaction.abort()
        response = Response(json.dumps(reason))
        response.status_int = 500
        return response


@view_config(request_method='GET', route_name='api_product_group_id', renderer='json', permission='Product Groups')
def show_id(request):
    return product_group_info(uuid.UUID(request.matchdict.get('id', None)))


@view_config(request_method='GET', route_name='api_product_group', renderer='json', permission='Product Groups')
def show_blank(request):
    return product_group_info(None)


@view_config(request_method='GET', route_name='api_product_group', request_param='l', renderer='json',
             permission='Authenticated')
def show_list(request):
    list = DBSession.query(ProductGroup).order_by(ProductGroup.header).order_by(ProductGroup.name).all()
    product_groups = []
    for item in list:
        product_groups.append({'Name': item.name, 'MaxDiscount': item.max_discount * 100, 'Header': item.header,
                               'IsActive': item.is_active, 'SortOrder': item.sort_order, 'IsFixture': item.is_fixture,
                               'Url': request.route_url('product_group_id', id=item.id)})
    return product_groups


@view_config(request_method='GET', route_name='api_product_group', request_param='t', renderer='json',
             permission='Authenticated')
def show_list(request):
    query = DBSession.query(ProductGroup) \
        .filter(ProductGroup.is_active == True) \
        .order_by(ProductGroup.sort_order).order_by(ProductGroup.name).all()
    product_groups = []
    for item in query:
        product_group = {'Name': item.name, 'MaxDiscount': item.max_discount * 100, 'Products': []}
        for product in DBSession.query(Product) \
            .filter(Product.product_group_id == item.id).filter(Product.is_active == True) \
            .order_by(Product.sort_order).order_by(Product.name).all():
            product_group['Products'].append(
                {'ProductID': product.id, 'Name': product.full_name, 'Price': product.price,
                 'HappyHour': product.happy_hour, 'ServiceCharge': product.service_charge,
                 'ScTaxable': product.sc_taxable, 'ServiceTax': product.service_tax.rate, 'Vat': product.vat.rate})
        product_groups.append(product_group)
    return product_groups


@view_config(request_method='GET', route_name='api_product_group', request_param='s', renderer='json',
             permission='Authenticated')
def show_small(request):
    list = DBSession.query(ProductGroup).order_by(ProductGroup.header).order_by(ProductGroup.name).all()
    product_groups = []
    for item in list:
        product_groups.append({'ProductGroupID': item.id, 'Name': item.name})
    return product_groups


def product_group_info(id):
    if id is None:
        return {'MaxDiscount': 100, 'SortOrder': 0, 'IsActive': True}
    else:
        product_group = ProductGroup.by_id(id)
        return {'ProductGroupID': product_group.id, 'Name': product_group.name,
                'MaxDiscount': product_group.max_discount * 100, 'Header': product_group.header,
                'IsActive': product_group.is_active, 'SortOrder': product_group.sort_order,
                'IsFixture': product_group.is_fixture}


def delete_with_data(product_group):
    #suspense_product = Product.by_id(Product.suspense())
    #suspense_batch = Batch.by_id(Batch.suspense())
    #query = Voucher.query().options(joinedload_all(Voucher.inventories, Inventory.product, innerjoin=True)) \
    #    .filter(Voucher.inventories.any(Inventory.product_id == tax.id)) \
    #    .all()
    #
    #for voucher in query:
    #    others, sus_inv, prod_inv = False, None, None
    #    for inventory in voucher.inventories:
    #        if inventory.product_id == tax.id:
    #            prod_inv = inventory
    #        elif inventory.product_id == Product.suspense():
    #            sus_inv = inventory
    #        else:
    #            others = True
    #    if not others and voucher.type == VoucherType.by_id('Issue'):
    #        DBSession.delete(voucher)
    #    else:
    #        if sus_inv is None:
    #            prod_inv.product = suspense_product
    #            prod_inv.quantity = prod_inv.amount
    #            prod_inv.rate = 1
    #            prod_inv.tax = 0
    #            prod_inv.discount = 0
    #            prod_inv.batch = suspense_batch
    #            voucher.narration += '\nSuspense \u20B9{0:,.2f} is {1}'.format(prod_inv.amount, tax.name)
    #        else:
    #            sus_inv.quantity += prod_inv.amount
    #            DBSession.delete(prod_inv)
    #            voucher.narration += '\nDeleted \u20B9{0:,.2f} of {1}'.format(prod_inv.amount, tax.name)
    #for batch in tax.batches:
    #    DBSession.delete(batch)
    DBSession.delete(product_group)
