# coding: utf-8

from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals

from saas.library.python.nanny_rest.enums import AllocationType
from saas.library.python.nanny_rest.resource import SandboxFile, StaticFile, UrlFile, TemplateSetFile
from saas.library.python.nanny_rest.shard_resource import RegisteredShard, SandboxShard, SandboxShardmap, sandbox_bsc_shard
from saas.library.python.nanny_rest.service_mutable_proxy.instance_spec import InstanceSpec

_RESOURCE_TYPE_MAPPING = {'sandbox_files': SandboxFile, 'static_files': StaticFile, 'url_files': UrlFile, 'template_set_files': TemplateSetFile}


class NannyServiceBaseRuntimeProxy(object):
    def __init__(self, nanny_service, initial_state):
        self.nanny_service = nanny_service
        resources = initial_state.pop('resources')
        self.instance_spec = InstanceSpec(nanny_service, **initial_state.pop('instance_spec'))

        self._resources = {}
        for resource_type, resource_class in _RESOURCE_TYPE_MAPPING.items():
            self._resources[resource_type] = [resource_class(**resource) for resource in resources[resource_type]]
        self._resources['sandbox_bsc_shard'] = sandbox_bsc_shard(resources['sandbox_bsc_shard']) if 'sandbox_bsc_shard' in resources else None
        self._extra_resources = {}
        for resource_type, resource_list in resources.items():
            if resource_type not in _RESOURCE_TYPE_MAPPING:
                self._extra_resources[resource_type] = resource_list
        self._runtime_attrs = initial_state

    @property
    def runtime_attrs_content(self):
        base = self._runtime_attrs
        base['resources'] = self._extra_resources
        for resource_type, resource_class in _RESOURCE_TYPE_MAPPING.items():
            base['resources'][resource_type] = [resource.dict() for resource in self._resources[resource_type]]

        if self._resources.get('sandbox_bsc_shard', None) is not None:
            base['resources']['sandbox_bsc_shard'] = self._resources['sandbox_bsc_shard'].dict()
        else:
            if 'sandbox_bsc_shard' in base['resources'].keys():
                del base['resources']['sandbox_bsc_shard']
        base['instance_spec'] = self.instance_spec.dict_repr()
        return base

    # Runtime attributes
    @property
    def allocation_type(self):
        return AllocationType(self._runtime_attrs['instances']['chosen_type'])

    @allocation_type.setter
    def allocation_type(self, value):
        self._runtime_attrs['instances']['chosen_type'] = value

    @property
    def resources(self):
        return self._resources

    def set_resource(self, resource):
        resources_to_remove = []
        current_resource_index = None, None
        for resource_type, current_resources in self._resources.items():
            if not isinstance(current_resources, list):
                pass
            else:
                for resource_index, current_resource in enumerate(current_resources):
                    if current_resource.local_path == resource.local_path:
                        if type(resource) == type(current_resource):
                            current_resource_index = resource_type, resource_index
                        else:
                            resources_to_remove.append((resource_type, resource_index))

        for resource_type, resource_index in resources_to_remove:
            del self._resources[resource_type][resource_index]

        if current_resource_index[1] is not None:
            self._resources[current_resource_index[0]][current_resource_index[1]] = resource
        else:
            reverse_mapping = {v: k for k, v in _RESOURCE_TYPE_MAPPING.items()}
            self._resources[reverse_mapping[type(resource)]].append(resource)

    # Specific resources
    @property
    def sandbox_files(self):
        return self.resources['sandbox_files']

    @sandbox_files.setter
    def sandbox_files(self, value):
        self._resources['sandbox_files'] = value

    @property
    def static_files(self):
        return self._resources['static_files']

    @static_files.setter
    def static_files(self, value):
        self._resources['static_files'] = value

    @property
    def url_files(self):
        return self._resources['url_files']

    @url_files.setter
    def url_files(self, value):
        self._resources['url_files'] = value

    @property
    def template_set_files(self):
        return self._resources['template_set_files']

    @template_set_files.setter
    def template_set_files(self, value):
        self._resources['template_set_files'] = value

    @property
    def shard(self):
        return self._resources.get('sandbox_bsc_shard', None)

    @shard.setter
    def shard(self, value):
        if isinstance(value, (RegisteredShard, SandboxShard, SandboxShardmap)):
            self._resources['sandbox_bsc_shard'] = value
        else:
            self._resources['sandbox_bsc_shard'] = sandbox_bsc_shard(value)
