from coralillo import Model, Form, BoundedModel, fields
from coralillo.validation import validation_rule
from coralillo.errors import InvalidFieldError
import sys
import inspect


# for model testing
class Table(Model):
    name = fields.Text()


class Ship(Model):
    name = fields.Text()
    code = fields.Text(index=True)


class Tenanted(BoundedModel):
    name = fields.Text()

    @classmethod
    def prefix(cls):
        return 'testing'


class SideWalk(Model):
    name = fields.Text()


class House(Model):
    number = fields.Integer(required=False)


# for events test
class Something(Model):
    name = fields.Text()
    notify = True


# for fields test
class Subscription(Model):
    key_name = fields.TreeIndex()


class User(Model):
    password = fields.Hash()


class Truck(Model):
    last_position = fields.Location()


# for form testing
class ShipForm(Form):
    name = fields.Text()
    code = fields.Text()


# for testing permissions
class Bunny(BoundedModel):
    name = fields.Text()

    @classmethod
    def prefix(cls):
        return 'bound'


# for testing validations
class MyForm(Form):
    field1 = fields.Text()
    field2 = fields.Text()

    @validation_rule
    def enforce_fields(data):
        if (data.field1 is None and data.field2 is None) or \
                (data.field1 is not None and data.field2 is not None):
            raise InvalidFieldError(field='field1')


class MyModel(Model):
    field1 = fields.Text(index=True, required=False, private=True)


# For testing relationships
class Pet(Model):
    name = fields.Text()
    owner = fields.ForeignIdRelation('coralillo.tests.models.Person', inverse='pets')


class Person(Model):
    name = fields.Text()
    pets = fields.SetRelation(Pet, on_delete='cascade', inverse='owner')


class UnattachedPerson(Model):
    name = fields.Text()
    pets = fields.SetRelation(Pet, on_delete='set_null', inverse='owner')


# For many to many relations
class Driver(Model):
    name = fields.Text()
    cars = fields.SetRelation('coralillo.tests.models.Car', inverse='drivers')


class Car(Model):
    name = fields.Text()
    drivers = fields.SetRelation(Driver, inverse='cars')


class Employee(Model):
    name = fields.Text()
    last_name = fields.Text()
    office = fields.ForeignIdRelation('coralillo.tests.models.Office', inverse='employees')


class Office(Model):
    name = fields.Text()
    address = fields.Text()
    employees = fields.SetRelation(Employee, inverse='office')


# for testing nested embedding
class A(Model):
    attr = fields.Text()
    bs = fields.SetRelation('coralillo.tests.models.B', inverse='a')


class B(Model):
    attr = fields.Text()
    a = fields.ForeignIdRelation(A, inverse='bs')
    cs = fields.SetRelation('coralillo.tests.models.C', inverse='b')


class C(Model):
    attr = fields.Text()
    b = fields.ForeignIdRelation(A, inverse='cs')


# For sorted set tests
class Admin(Model):
    name = fields.Text()
    logs = fields.SortedSetRelation('coralillo.tests.models.Log', sort_key='date', inverse='owner')


class Log(Model):
    data = fields.Text()
    date = fields.Datetime()
    owner = fields.ForeignIdRelation(Admin, inverse='logs')


def bound_models(eng):
    for name, cls in inspect.getmembers(sys.modules[__name__]):
        if inspect.isclass(cls):
            if issubclass(cls, Form):
                cls.set_engine(eng)
