import json

__author__ = 'tanshu'

from decimal import Decimal
import uuid

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

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


@view_config(route_name='product_list', permission='Authenticated')
@view_config(request_method='GET', route_name='product_id', permission='Products')
@view_config(request_method='GET', route_name='product', permission='Products')
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', renderer='json', permission='Products')
@TryCatchFunction
def save(request):
    json = request.json_body
    name = json.get('Name', '').strip()
    if name == '':
        raise ValidationError('Validation', 'Name cannot be blank')
    units = json.get('Units', '').strip()
    product_group_id = uuid.UUID(json['ProductGroupID'])
    price = Decimal(json.get('Price', 0))
    happy_hour = json.get('HappyHour', False)
    service_tax_id = uuid.UUID(json['ServiceTaxID'])
    vat_id = uuid.UUID(json['VatID'])
    service_charge = round(Decimal(json.get('ServiceCharge', 0)) / 100, 5)
    sc_taxable = json['ScTaxable']
    is_active = json['IsActive']
    sort_order = json['SortOrder']

    item = Product(0, name, units, product_group_id, price, happy_hour, service_tax_id, vat_id, service_charge,
                   sc_taxable, is_active, sort_order).create()
    transaction.commit()
    return product_info(item.id)


@view_config(request_method='POST', route_name='api_product_id', renderer='json', permission='Products')
@TryCatchFunction
def update(request):
    item = Product.by_id(uuid.UUID(request.matchdict['id']))
    if item.is_fixture:
        raise ValidationError('Fixture', "{0} cannot be edited or deleted.".format(item.full_name))
    name = request.json_body['Name'].strip()
    if name == '':
        raise ValidationError('Validation', 'Name cannot be blank')
    item.name = name
    item.units = request.json_body['Units'].strip()
    item.product_group_id = uuid.UUID(request.json_body['ProductGroupID'])
    item.price = Decimal(request.json_body.get('Price', 0))
    item.price = Decimal(request.json_body.get('Price', 0))
    item.happy_hour = request.json_body.get('HappyHour', False)
    item.service_tax_id = uuid.UUID(request.json_body['ServiceTaxID'])
    item.vat_id = uuid.UUID(request.json_body['VatID'])
    item.service_charge = round(Decimal(request.json_body.get('ServiceCharge', 0)) / 100, 5)
    item.sc_taxable = request.json_body['ScTaxable']
    item.is_active = request.json_body['IsActive']
    item.sort_order = request.json_body['SortOrder']
    transaction.commit()
    return product_info(item.id)


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

    if can_delete:
        delete_with_data(product)
        transaction.commit()
        return product_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_id', renderer='json', permission='Products')
def show_id(request):
    return product_info(uuid.UUID(request.matchdict.get('id', None)))


@view_config(request_method='GET', route_name='api_product', renderer='json', permission='Products')
def show_blank(request):
    return product_info(None)


@view_config(request_method='GET', route_name='api_product', request_param='l', renderer='json',
             permission='Authenticated')
def show_list(request):
    list = Product.query().order_by(Product.is_active.desc()).order_by(Product.product_group_id).order_by(
        Product.name).all()
    products = []
    for item in list:
        products.append(
            {'Code': item.code, 'Name': item.full_name, 'ProductGroup': item.product_group.name, 'Price': item.price,
             'HappyHour': item.happy_hour, 'ServiceTax': item.service_tax.name,
             'ServiceTaxRate': item.service_tax.rate * 100, 'Vat': item.vat.name, 'VatRate': item.vat.rate * 100,
             'ServiceCharge': item.service_charge * 100, 'ScTaxable': item.sc_taxable, 'IsActive': item.is_active,
             'IsFixture': item.is_fixture, 'SortOrder': item.sort_order,
             'Url': request.route_url('product_id', id=item.id)})
    return products


@view_config(request_method='GET', route_name='api_product', renderer='json', request_param='q',
             permission='Authenticated')
def show_term(request):
    term = request.GET.get('term', None)
    term = term if term is not None and term is not '' else None
    active = request.GET.get('a', None)
    active = active if active is not None else None
    count = request.GET.get('count', None)
    count = None if count is None or count == '' else int(count)
    list = []
    for index, item in enumerate(Product.list(term, active)):
        list.append({'ProductID': item.id, 'Name': item.full_name, 'Price': item.price})
        if count is not None and index == count - 1:
            break
    return list


def product_info(id):
    if id is None:
        product = {'Code': '(Auto)', 'HappyHour': False, 'ScTaxable': False, 'ServiceTaxID': Tax.tax_free_id(),
                   'VatID': Tax.tax_free_id(), 'IsActive': True, 'SortOrder': 0}
    else:
        product = Product.by_id(id)
        product = {'ProductID': product.id, 'Code': product.code, 'Name': product.name, 'Units': product.units,
                   'ProductGroupID': product.product_group_id, 'Price': product.price, 'HappyHour': product.happy_hour,
                   'ServiceTaxID': product.service_tax_id, 'VatID': product.vat_id,
                   'ServiceCharge': product.service_charge * 100, 'ScTaxable': product.sc_taxable,
                   'IsActive': product.is_active, 'SortOrder': product.sort_order}
    return product


def delete_with_data(product):
    pass
    #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 == product.id)) \
    #    .all()
    #
    #for voucher in query:
    #    others, sus_inv, prod_inv = False, None, None
    #    for inventory in voucher.inventories:
    #        if inventory.product_id == product.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, product.name)
    #        else:
    #            sus_inv.quantity += prod_inv.amount
    #            DBSession.delete(prod_inv)
    #            voucher.narration += '\nDeleted \u20B9{0:,.2f} of {1}'.format(prod_inv.amount, product.name)
    #for batch in product.batches:
    #    DBSession.delete(batch)
    DBSession.delete(product)
