from typing import Dict, List
from common.orm.fields.IntegerField import IntegerField
from common.orm.fields.StringField import StringField
from common.orm.model.Model import Model
from common.orm.fields.ForeignKeyField import ForeignKeyField
from common.orm.fields.PrimaryKeyField import PrimaryKeyField

class ContextModel(Model):
    pk = PrimaryKeyField()

    def dump_id(self) -> Dict:
        return {'context_uuid': {'uuid': self.pk}}

    def dump_service_ids(self) -> List[Dict]:
        db_service_pks = self.references(ServiceModel)
        return [ServiceModel(self.database, pk, auto_load=False).dump_id() for pk in db_service_pks]

    def dump_topology_ids(self) -> List[Dict]:
        db_topology_pks = self.references(TopologyModel)
        return [TopologyModel(self.database, pk, auto_load=False).dump_id() for pk in db_topology_pks]

    def dump(self, include_services=True, include_topologies=True) -> Dict: # pylint: disable=arguments-differ
        result = {'context_id': self.dump_id()}
        if include_services: result['service_ids'] = self.dump_service_ids()
        if include_topologies: result['topology_ids'] = self.dump_topology_ids()
        return result

class TopologyModel(Model):
    pk = PrimaryKeyField()
    context_fk = ForeignKeyField(ContextModel)

    def dump_id(self) -> Dict:
        context_id = ContextModel(self.database, self.context_fk, auto_load=False).dump_id()
        return {
            'context_id': context_id,
            'topology_uuid': {'uuid': self.pk.split('/')[-1]},
        }

    def dump_device_ids(self) -> List[Dict]:
        db_device_pks = self.references(DeviceModel)
        return [DeviceModel(self.database, pk, auto_load=False).dump_id() for pk in db_device_pks]

    def dump_link_ids(self) -> List[Dict]:
        db_link_pks = self.references(LinkModel)
        return [LinkModel(self.database, pk, auto_load=False).dump_id() for pk in db_link_pks]

    def dump(self, include_devices=True, include_links=True) -> Dict: # pylint: disable=arguments-differ
        result = {'topology_id': self.dump_id()}
        if include_devices: result['device_ids'] = self.dump_device_ids()
        if include_links: result['link_ids'] = self.dump_link_ids()
        return result

class DeviceModel(Model):
    pk = PrimaryKeyField()
    device_type = StringField()

class TopologyDeviceModel(Model):
    pk = PrimaryKeyField()
    topology_fk = ForeignKeyField(TopologyModel)
    device_fk = ForeignKeyField(DeviceModel)

class DeviceConfigModel(Model):
    pk = PrimaryKeyField()
    device_fk = ForeignKeyField(DeviceModel)

class DeviceConfigRuleModel(Model):
    pk = PrimaryKeyField()
    device_config_fk = ForeignKeyField(DeviceConfigModel)
    position = IntegerField(min_value=0, required=True)
    key = StringField(required=True)
    value = StringField(required=True)

#message Device {
#  DeviceConfig device_config = 3;
#  DeviceOperationalStatus devive_operational_status = 4;
#  repeated DeviceDriverEnum device_drivers = 5;
#  repeated EndPoint endpoints = 6;
#}

class LinkModel(Model):
    link_uuid = PrimaryKeyField()

class TopologyLinkModel(Model):
    topology_fk = ForeignKeyField(TopologyModel)
    link_fk = ForeignKeyField(LinkModel)

class EndPointModel(Model):
    endpoint_uuid = PrimaryKeyField()

class ServiceModel(Model):
    endpoint_uuid = PrimaryKeyField()


# TODO: implement query methods to find, for instance, topologies belonging to a context
#  from Context instance, retrieve references of a specific Model type
