__author__ = 'tanshu'

import uuid
from sqlalchemy import UniqueConstraint, Column, Integer, Unicode, Numeric, Boolean, ForeignKey, func, PickleType
from sqlalchemy.orm import relationship
from ..models import Base, DBSession
from ..models.guidtype import GUID


class Product(Base):
    __tablename__ = 'products'
    __tableagrs__ = (UniqueConstraint('name', 'units'))

    id = Column('product_id', GUID(), primary_key=True, default=uuid.uuid4)
    code = Column('code', Integer, unique=True, nullable=False)
    name = Column('name', Unicode(255), nullable=False)
    units = Column('units', Unicode(255), nullable=False)
    product_group_id = Column('product_group_id', GUID(), ForeignKey('product_groups.product_group_id'), nullable=False)
    price = Column('price', Numeric, nullable=False)
    happy_hour = Column('happy_hour', Boolean, nullable=False)
    service_tax_id = Column('service_tax_id', GUID(), ForeignKey('taxes.tax_id'), 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)

    is_active = Column('is_active', Boolean, nullable=False)
    is_fixture = Column('is_fixture', Boolean, nullable=False)
    sort_order = Column('sort_order', Integer, nullable=False)

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

    def __init__(self, code=None, name=None, units=None, product_group_id=None, price=None, happy_hour=None,
                 service_tax_id=None, vat_id=None, service_charge=None, sc_taxable=None, is_active=None,
                 sort_order=None, is_fixture=False):
        self.code = code
        self.name = name
        self.units = units
        self.product_group_id = product_group_id
        self.price = price
        self.happy_hour = happy_hour
        self.service_tax_id = service_tax_id
        self.vat_id = vat_id
        self.service_charge = service_charge
        self.sc_taxable = sc_taxable
        self.is_active = is_active
        self.sort_order = sort_order
        self.is_fixture = is_fixture

    @property
    def full_name(self):
        return "{0} ({1})".format(self.name, self.units)

    @classmethod
    def list(cls, name, active):
        query = DBSession.query(cls)
        if active is not None:
            query = query.filter(cls.is_active != active)
        for item in name.split():
            query = query.filter(cls.name.ilike('%' + item + '%'))
        return query.order_by(cls.name)

    @classmethod
    def by_name(cls, name):
        return DBSession.query(cls).filter(cls.name == name).first()

    @classmethod
    def by_full_name(cls, full_name):
        return DBSession.query(cls).filter(cls.name + ' (' + cls.units + ')' == full_name).first()

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

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

    def create(self):
        code = DBSession.query(func.max(Product.code)).one()[0]
        if code is None:
            self.code = 1
        else:
            self.code = code + 1
        DBSession.add(self)
        return self

    def can_delete(self, advanced_delete):
        if self.is_fixture:
            return False, ('Fixture', "{0} cannot be edited or deleted.".format(self.name))
        if self.is_active:
            return False, ('Active', 'Product is active')
        if len(self.inventories) > 0 and not advanced_delete:
            return False, ('In Use', 'Product has entries')
        return True, ''

    @classmethod
    def suspense(cls):
        return uuid.UUID('aa79a643-9ddc-4790-ac7f-a41f9efb4c15')


class ProductGroup(Base):
    __tablename__ = 'product_groups'

    id = Column('product_group_id', GUID(), primary_key=True, default=uuid.uuid4)
    name = Column('name', Unicode(255), unique=True, nullable=False)
    max_discount = Column('max_discount', Numeric, nullable=False)
    header = Column('header', Unicode(255), nullable=False)

    is_active = Column('is_active', Boolean, nullable=False)
    is_fixture = Column('is_fixture', Boolean, nullable=False)
    sort_order = Column('sort_order', Integer, nullable=False)

    products = relationship('Product', backref='product_group')

    def __init__(self, name=None, max_discount=1, header=None, sort_order=None, is_active=True, id=None,
                 is_fixture=False):
        self.name = name
        self.max_discount = max_discount
        self.header = header
        self.sort_order = sort_order
        self.is_active = is_active
        if id is not None and not isinstance(id, uuid.UUID):
            id = uuid.UUID(id)
        self.id = id
        self.is_fixture = is_fixture

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

    @classmethod
    def by_id(cls, id):
        if not isinstance(id, uuid.UUID):
            id = uuid.UUID(id)
        return DBSession.query(cls).filter(cls.id == id).first()

    def can_delete(self, advanced_delete):
        if self.is_fixture:
            return False, ('Fixture', "{0} cannot be edited or deleted.".format(self.name))
            #if len(self.inventories) > 0 and not advanced_delete:
        #    return False, 'Product has entries'
        return True, ''


class Tax(Base):
    __tablename__ = 'taxes'

    id = Column('tax_id', GUID(), primary_key=True, default=uuid.uuid4)
    name = Column('name', Unicode(255), unique=True, nullable=False)
    rate = Column('rate', Numeric, nullable=False)
    is_fixture = Column('is_fixture', Boolean, nullable=False)

    def __init__(self, name=None, rate=None, id=None, is_fixture=False):
        if id is not None and not isinstance(id, uuid.UUID):
            id = uuid.UUID(id)
        self.id = id
        self.name = name
        self.rate = rate
        self.is_fixture = is_fixture

    @classmethod
    def by_id(cls, id):
        if not isinstance(id, uuid.UUID):
            id = uuid.UUID(id)
        return DBSession.query(cls).filter(cls.id == id).first()

    @classmethod
    def by_name(cls, name):
        return DBSession.query(cls).filter(cls.name == name).first()

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

    def can_delete(self, advanced_delete):
        if self.is_fixture:
            return False, ('Fixture', "{0} cannot be edited or deleted.".format(self.name))
            #if len(self.inventories) > 0 and not advanced_delete:
            #    return False, 'Product has entries'
        return True, ''

    @classmethod
    def tax_free_id(cls):
        return uuid.UUID('08c3101d-cdab-449f-9574-a025c8ae5556')

    @classmethod
    def tax_free(cls):
        return {'TaxID': uuid.UUID('08c3101d-cdab-449f-9574-a025c8ae5556')}


class DbSetting(Base):
    __tablename__ = 'auth_settings'

    id = Column('setting_id', GUID(), primary_key=True, default=uuid.uuid4)
    name = Column('name', Unicode(255), unique=True, nullable=False)
    data = Column('data', PickleType)

    def __init__(self, id=None, name=None, data=None):
        self.id = id
        self.name = name
        self.data = data

    @classmethod
    def by_id(cls, id):
        if not isinstance(id, uuid.UUID):
            id = uuid.UUID(id)
        return DBSession.query(cls).filter(cls.id == id).first()

    @classmethod
    def by_name(cls, name):
        return DBSession.query(cls).filter(cls.name == name).first()

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


class FoodTable(Base):
    __tablename__ = 'food_tables'

    id = Column('food_table_id', GUID(), primary_key=True, default=uuid.uuid4)
    name = Column('name', Unicode(255), unique=True, nullable=False)
    location = Column('location', Unicode(255), nullable=False)

    def __init__(self, name=None, location=None, id=None):
        self.id = id
        self.name = name
        self.location = location

    @classmethod
    def by_id(cls, id):
        if not isinstance(id, uuid.UUID):
            id = uuid.UUID(id)
        return DBSession.query(cls).filter(cls.id == id).first()

    @classmethod
    def by_name(cls, name):
        return DBSession.query(cls).filter(cls.name == name).first()

    @classmethod
    def by_normalized_name(cls, name):
        return DBSession.query(cls).filter(cls.name == name.replace('-', ' ')).first()

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

    def can_delete(self, advanced_delete):
    #if len(self.inventories) > 0 and not advanced_delete:
        #    return False, 'Product has entries'
        return True, ''


class TableStatus:
    def __init__(self, id, status):
        self.id = id
        self.status = status

    @classmethod
    def list(cls):
        list = []
        list.append(TableStatus(1, 'Locked'))
        list.append(TableStatus(2, 'Running'))
        list.append(TableStatus(3, 'Billed'))
        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 Modifier(Base):
    __tablename__ = 'modifiers'

    id = Column('modifier_id', GUID(), primary_key=True, default=uuid.uuid4)
    name = Column('name', Unicode(255), unique=True, nullable=False)
    is_active = Column('is_active', Boolean, nullable=False)

    groups = relationship('ModifierProductGroup', backref='modifier')

    def __init__(self, name=None, is_active=None, id=None):
        self.id = id
        self.name = name
        self.is_active = is_active

    @classmethod
    def by_id(cls, id):
        if not isinstance(id, uuid.UUID):
            id = uuid.UUID(id)
        return DBSession.query(cls).filter(cls.id == id).first()

    @classmethod
    def by_name(cls, name):
        return DBSession.query(cls).filter(cls.name == name).first()

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

    def can_delete(self, advanced_delete):
    #if len(self.inventories) > 0 and not advanced_delete:
        #    return False, 'Product has entries'
        return True, ''


class ModifierProductGroup(Base):
    __tablename__ = 'modifier_product_groups'

    id = Column('modifier_product_groups_id', GUID(), primary_key=True, default=uuid.uuid4)
    modifier_id = Column('modifier_id', GUID(), ForeignKey('modifiers.modifier_id'), nullable=False)
    product_group_id = Column('product_group_id', GUID(), ForeignKey('product_groups.product_group_id'), nullable=True)

    group = relationship('ProductGroup', backref='modifiers')

    def __init__(self, modifier_id=None, product_group_id=None, id=None):
        self.id = id
        self.modifier_id = modifier_id
        self.product_group_id = product_group_id
