import os
import base64
from collections import defaultdict
from django.db.models import F, Q
from xos.config import Config
from synchronizers.base.openstacksyncstep import OpenStackSyncStep
from synchronizers.base.syncstep import *
from core.models import Controller
from core.models import Image, ControllerImages
from xos.logger import observer_logger as logger
from synchronizers.base.ansible import *
from services.vrouter.models import VRouterTenant
from services.onos.models import ONOSService
from services.fabric.models import FabricService
import json

class SyncVRouterTenant(SyncStep):
    provides=[VRouterTenant]
    observes = VRouterTenant
    requested_interval=30
    playbook='sync_host.yaml'

    def get_files_dir(self):
        if not hasattr(Config(), "observer_steps_dir"):
            # make steps_dir mandatory; there's no valid reason for it to not
            # be defined.
            raise Exception("observer_steps_dir is not defined in config file")

        step_dir = Config().observer_steps_dir

        return os.path.join(step_dir, "..", "files")

    def get_fabric_onos_service(self):
        fos = None
        fs = FabricService.get_service_objects().all()[0]
        if fs.subscribed_tenants.exists():
            app = fs.subscribed_tenants.all()[0]
            if app.provider_service:
                ps = app.provider_service
                fos = ONOSService.get_service_objects().filter(id=ps.id)[0]
        return fos

    def get_node_tag(self, node, tagname):
        tags = Tag.select_by_content_object(node).filter(name=tagname)
        return tags[0].value

    def fetch_pending(self, deleted):
        fs = FabricService.get_service_objects().all()[0]
        if not fs.autoconfig:
            return None

        if (not deleted):
            objs = VRouterTenant.get_tenant_objects().filter(Q(lazy_blocked=False))
        else:
            objs = VRouterTenant.get_deleted_tenant_objects()

        # Check that each is a valid vCPE tenant or instance
        for vroutertenant in objs:
            # Do we have a vCPE subscriber_tenant?
            if vroutertenant.subscriber_tenant:
                sub = vroutertenant.subscriber_tenant
                if sub.kind != 'vCPE' or not sub.get_attribute("instance_id"):
                    objs.remove(vroutertenant)
            else:
                # Maybe the VRouterTenant is for an instance
                instance_id = vroutertenant.get_attribute("tenant_for_instance_id")
                if not instance_id:
                    objs.remove(vroutertenant)
                else:
                    instance = Instance.objects.filter(id=instance_id)[0]
                    if not instance.instance_name:
                        objs.remove(vroutertenant)

        return objs

    def write_config(self, files_dir, name, public_mac, public_ip, location):
        if not os.path.exists(files_dir):
            os.makedirs(files_dir)

        # Create JSON
        data = {
            "%s/-1"%public_mac : {
                "basic" : {
                    "ips" : [ public_ip ],
                    "location" : location
                }
            }
        }

        file(os.path.join(files_dir, name),"w").write(json_dumps(data,indent=4))

    def map_sync_inputs(self, vroutertenant):

        fos = self.get_fabric_onos_service()

        name = None
        instance = None
        # VRouterTenant setup is kind of hacky right now, we'll
        # need to revisit.  The idea is:
        # * Look up the instance corresponding to the address
        # * Look up the node running the instance
        # * Get the "location" tag, push to the fabric
        if vroutertenant.subscriber_tenant:
            sub = vroutertenant.subscriber_tenant
            instance_id = sub.get_attribute("instance_id")
            instance = Instance.objects.filter(id=instance_id)[0]
            name = str(sub)
        else:
            instance_id = vroutertenant.get_attribute("tenant_for_instance_id")
            instance = Instance.objects.filter(id=instance_id)[0]
            name = str(instance)

        node = instance.node
        location = self.get_node_tag(node, "location")

        files_dir = self.get_files_dir()
        self.write_config(files_dir, name, vroutertenant.public_mac, vroutertenant.public_ip, location)

        # Is it a POST or DELETE?

        fields = {
            'rest_hostname': fos.rest_hostname,
            'rest_port': fos.rest_port,
            'rest_endpoint': "onos/v1/network/configuration/hosts",
            'files_dir': files_dir,
            'rest_config.fn': name,
            'ansible_tag': '%s'%name, # name of ansible playbook
        }
        return fields

    def map_sync_outputs(self, controller_image, res):
        pass
