from picard.models.master import Tax

__author__ = 'tanshu'

import uuid

from sqlalchemy.ext.hybrid import hybrid_property
from sqlalchemy import Column, Integer, DateTime, Numeric, ForeignKey, Boolean, UniqueConstraint
from sqlalchemy.orm import relationship, synonym, backref

from ..models.guidtype import GUID
from ..models import Base, DBSession


class VoucherType:
    def __init__(self, id, name, show_in_choices, group):
        self.id = id
        self.name = name
        self.show_in_choices = show_in_choices
        self.group = group

    @classmethod
    def list(cls):
        list = []
        list.append(VoucherType(1, 'Regular Bill', True, 2))
        list.append(VoucherType(2, 'No Charge', True, 3))
        list.append(VoucherType(3, 'Take Away', True, 2))
        list.append(VoucherType(4, 'Staff Bill', True, 4))
        return list

    @classmethod
    def by_name(cls, name):
        list = cls.list()
        for item in list:
            if item.name == name:
                return item


    @classmethod
    def by_id(cls, id):
        list = cls.list()
        for item in list:
            if item.id == id:
                return item


class Voucher(Base):
    __tablename__ = 'vouchers'
    __tableagrs__ = (UniqueConstraint('voucher_type', 'bill_id'))
    id = Column('voucher_id', GUID(), primary_key=True, default=uuid.uuid4)
    date = Column('date', DateTime(timezone=True), nullable=False)
    creation_date = Column('creation_date', DateTime(timezone=True), nullable=False)
    last_edit_date = Column('last_edit_date', DateTime(timezone=True), nullable=False)
    _type = Column('voucher_type', Integer, nullable=False)
    kot_id = Column('kot_id', Integer, unique=True, nullable=False)
    bill_id = Column('bill_id', Integer, nullable=True)
    pax = Column('pax', Integer, nullable=False)
    per_chair = Column('per_chair', Boolean, nullable=False)

    user_id = Column('user_id', GUID(), ForeignKey('auth_users.user_id'), nullable=False)
    food_table_id = Column('table_id', GUID(), ForeignKey('food_tables.food_table_id'), nullable=False)

    user = relationship('User', primaryjoin="User.id==Voucher.user_id", cascade=None)
    food_table = relationship('FoodTable', primaryjoin="FoodTable.id==Voucher.food_table_id", cascade=None)

    kots = relationship('Kot', backref='voucher', cascade="delete, delete-orphan", cascade_backrefs=False)

    def _get_type(self):
        return self._type
        # for item in VoucherType.list():
        # if self._type == item.id:
        # return item

    def _set_type(self, value):
        if type(value) == int:
            self._type = value
        else:
            self._type = value.id

    type = property(_get_type, _set_type)
    type = synonym('_type', descriptor=type)

    @property
    def __name__(self):
        return self.name

    def __init__(self, date=None, creation_date=None, last_edit_date=None, type=None, kot_id=None, bill_id=None,
                 user_id=None, food_table_id=None, pax=None, per_seat=None, id=None):
        self.id = id
        self.date = date
        self.creation_date = creation_date
        self.last_edit_date = last_edit_date
        self.type = type
        self.kot_id = kot_id
        self.bill_id = bill_id
        self.user_id = user_id
        self.food_table_id = food_table_id
        self.pax = pax
        self.per_seat = per_seat

    @classmethod
    def by_id(cls, id):
        return DBSession.query(cls).filter(cls.id == id).first()

    @classmethod
    def list(cls):
        return DBSession.query(cls).all()

    @classmethod
    def query(cls):
        return DBSession.query(cls)


class Kot(Base):
    __tablename__ = 'kots'

    id = Column('kot_id', GUID(), primary_key=True, default=uuid.uuid4)
    voucher_id = Column('voucher_id', GUID(), ForeignKey('vouchers.voucher_id'), nullable=False)
    code = Column('code', Integer, unique=True, nullable=False)
    food_table_id = Column('table_id', GUID(), ForeignKey('food_tables.food_table_id'), nullable=False)
    date = Column('date', DateTime, nullable=False)
    user_id = Column('user_id', GUID(), ForeignKey('auth_users.user_id'), nullable=False)

    food_table = relationship('FoodTable', primaryjoin="FoodTable.id==Kot.food_table_id", cascade=None)

    @hybrid_property
    def signed_amount(self):
        return self.debit * self.amount

    @property
    def __name__(self):
        return self.name

    def __init__(self, code=None, food_table_id=None, date=None, user_id=None, voucher_id=None, id=None):
        self.id = id
        self.voucher_id = voucher_id
        self.code = code
        self.food_table_id = food_table_id
        self.date = date
        self.user_id = user_id

    @classmethod
    def by_id(cls, id):
        return DBSession.query(cls).filter(cls.id == id).first()

    @classmethod
    def list(cls, voucher_id):
        return DBSession.query(cls).filter(cls.voucher_id == voucher_id).all()

    @classmethod
    def query(cls):
        return DBSession.query(cls)


class Inventory(Base):
    __tablename__ = 'inventories'
    #        __tableagrs__ = (UniqueConstraint('VoucherID', 'ProductID'))
    id = Column('inventory_id', GUID(), primary_key=True, default=uuid.uuid4)
    kot_id = Column('kot_id', GUID(), ForeignKey('kots.kot_id'), nullable=False)
    chair = Column('chair', Integer, nullable=False)
    product_id = Column('product_id', GUID(), ForeignKey('products.product_id'), nullable=False)
    quantity = Column('quantity', Numeric, nullable=False)
    price = Column('rate', Numeric, nullable=False)
    discount = Column('discount', Numeric, nullable=False)
    is_happy_hour = Column('is_happy_hour', Boolean, nullable=False)
    _service_tax_rate = Column('service_tax_rate', Numeric, nullable=False)
    service_tax_id = Column('service_tax_id', GUID(), ForeignKey('taxes.tax_id'), nullable=False)
    _vat_rate = Column('vat_rate', Numeric, nullable=False)
    vat_id = Column('vat_id', GUID(), ForeignKey('taxes.tax_id'), nullable=False)

    service_charge = Column('service_charge', Numeric, nullable=False)
    sc_taxable = Column('sc_taxable', Boolean, nullable=False)

    service_tax = relationship('Tax', foreign_keys=service_tax_id)
    vat = relationship('Tax', foreign_keys=vat_id)

    def __init__(self, chair=0, product_id=None, quantity=None, price=None, discount=None, is_happy_hour=None,
                 service_tax_id=None, service_tax_rate=None, vat_id=None, vat_rate=None, service_charge=None,
                 sc_taxable=None, kot_id=None, id=None):
        self.id = id
        self.kot_id = kot_id
        self.chair = chair
        self.product_id = product_id
        self.quantity = quantity
        self.price = price
        self.discount = discount
        self.is_happy_hour = is_happy_hour
        self.service_tax_id = service_tax_id
        self.service_tax_rate = service_tax_rate
        self.vat_id = vat_id
        self.vat_rate = vat_rate
        self.service_charge = service_charge
        self.sc_taxable = sc_taxable

    def _get_service_tax_rate(self):
        if self._service_tax_rate is not None:
            return self._service_tax_rate
        if self.service_tax is not None:
            return self.service_tax.rate
        if self.service_tax_id is not None:
            return Tax.by_id(self.service_tax_id).rate
        return None

    def _set_service_tax_rate(self, value):
        self._service_tax_rate = value

    service_tax_rate = property(_get_service_tax_rate, _set_service_tax_rate)
    service_tax_rate = synonym('_service_tax_rate', descriptor=service_tax_rate)

    def _get_vat_rate(self):
        if self._vat_rate is not None:
            return self._vat_rate
        if self.vat is not None:
            return self.vat.rate
        if self.vat_id is not None:
            return Tax.by_id(self.vat_id).rate
        return None

    def _set_vat_rate(self, value):
        self._vat_rate = value

    vat_rate = property(_get_vat_rate, _set_vat_rate)
    vat_rate = synonym('_vat_rate', descriptor=vat_rate)

    @hybrid_property
    def amount(self):
        if self.is_happy_hour:
            return 0
        base = self.quantity * self.rate * (1 - self.discount)
        if self.sc_taxable:
            return base * (1 + self.service_charge) * (1 + self.service_tax_rate + self.vat_rate)
        return base * (1 + self.service_charge + self.service_tax_rate + self.vat_rate)


class RunningTable(Base):
    __tablename__ = 'running_tables'
    id = Column('running_table_id', GUID(), primary_key=True, default=uuid.uuid4)
    voucher_id = Column('voucher_id', GUID(), ForeignKey('vouchers.voucher_id'), nullable=False, unique=True)
    food_table_id = Column('food_table_id', GUID(), ForeignKey('food_tables.food_table_id'), nullable=False,
                           unique=True)
    _status = Column('table_status', Integer, nullable=False)

    food_table = relationship('FoodTable', backref=backref('info', uselist=False))

    def _get_status(self):
        for item in RunningTable.list():
            if self._status == item.id:
                return item

    def _set_status(self, value):
        if type(value) == int:
            self._status = value
        else:
            self._status = value.id

    status = property(_get_status, _set_status)
    status = synonym('_status', descriptor=status)

    def __init__(self, id=None, voucher_id=None, food_table_id=None, status=None):
        self.id = id
        self.voucher_id = voucher_id
        self.food_table_id = food_table_id
        self.status = status
