# coding: utf-8

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

import json
from copy import deepcopy

from collections import namedtuple
from library.python import resource


class InstanceDataVolume(object):
    __slots__ = ('name', 'type', 'version',)
    TYPE = None
    TEMPLATE_DICT = json.loads(resource.find('saas/library/nanny/instance_data_volume.json'))

    def __init__(self, name, type, version='', ):
        self.name = name
        self.type = type
        self.version = version

    def dict(self):
        new_dict = deepcopy(self.TEMPLATE_DICT)
        new_dict['name'] = self.name
        new_dict['type'] = self.type
        new_dict['version'] = self.version
        return new_dict

    def __hash__(self):
        return hash((self.name, self.type))


class VaultSecretVolume(InstanceDataVolume):
    __slots__ = ('secretId', 'secretVer', 'delegationToken', 'secretName')
    TYPE = 'VAULT_SECRET'

    def __init__(self, name, secretId, secretVer=None, delegationToken=None, secretName=None, **kwargs):
        super(VaultSecretVolume, self).__init__(
            name=name, type=self.TYPE, version=kwargs.get('version', '')
        )
        self.secretId = secretId
        self.secretVer = secretVer
        self.delegationToken = delegationToken
        self.secretName = secretName

    def dict(self):
        base_dict = super(VaultSecretVolume, self).dict()
        base_dict['vaultSecretVolume']['vaultSecret'] = {k: getattr(self, k) for k in self.__slots__}
        return base_dict

    def __eq__(self, other):
        if isinstance(other, VaultSecretVolume):
            return self.secretId == other.secretId
        else:
            return False


class SecretVolume(InstanceDataVolume):
    __slots__ = ('secretName', 'keychainId', 'secretId', 'secretRevisionId')
    TYPE = 'SECRET'

    def __init__(self, name, keychainId, secretId, secretRevisionId, secretName='', **kwargs):
        super(SecretVolume, self).__init__(name=name, type=self.TYPE, version=kwargs.get('version', ''))
        self.secretName = secretName
        self.keychainId = keychainId
        self.secretId = secretId
        self.secretRevisionId = secretRevisionId

    def dict(self):
        base_dict = super(SecretVolume, self).dict()
        base_dict['secretVolume'] = {
            'secretName': self.secretName,
            'keychainSecret': {
                'keychainId': self.keychainId,
                'secretId': self.secretId,
                'secretRevisionId': self.secretRevisionId
            }
        }
        return base_dict

    def __eq__(self, other):
        if isinstance(other, SecretVolume):
            return self.keychainId == other.keychainId and self.secretId == other.secretId
        else:
            return False


class ItsVolume(InstanceDataVolume):
    __slots__ = ('maxRetryPeriodSeconds', 'periodSeconds', 'itsUrl')
    TYPE = 'ITS'
    PATH = 'itsVolume'

    def __init__(self, name, itsUrl='http://its.yandex-team.ru/v1',
                 periodSeconds=60,  # How often (in seconds) to poll controls from ITS
                 maxRetryPeriodSeconds=300,  # Maximal period beetween poll retries
                 **kwargs):
        super(ItsVolume, self).__init__(name=name, type=self.TYPE, version=kwargs.get('version', ''))
        self.maxRetryPeriodSeconds = maxRetryPeriodSeconds
        self.periodSeconds = periodSeconds
        self.itsUrl = itsUrl

    def dict(self):
        base_dict = super(ItsVolume, self).dict()
        base_dict[self.PATH] = {{k: getattr(self, k) for k in self.__slots__}}
        return base_dict

    def __eq__(self, other):
        if isinstance(other, ItsVolume):
            return (
                self.itsUrl == other.itsUrl and
                self.periodSeconds == other.periodSeconds and
                self.maxRetryPeriodSeconds == other.maxRetryPeriodSeconds
            )
        else:
            return False


class TemplateVolume(InstanceDataVolume):
    __slots__ = ('template', )
    TYPE = 'TEMPLATE'
    PATH = 'templateVolume'
    Template = namedtuple('Template', ('srcPath', 'dstPath'))

    def __init__(self, name, template, **kwargs):
        super(TemplateVolume, self).__init__(name=name, type=self.TYPE, version=kwargs.get('version', ''))
        self.template = [self.Template(**t) for t in template]

    def dict(self):
        base_dict = super(TemplateVolume, self).dict()
        base_dict[self.PATH] = {
            'template': [{'srcPath': t.srcPath, 'dstPath': t.dstPath} for t in self.template]
        }

    def __eq__(self, other):
        if isinstance(other, TemplateVolume):
            return self.template == other.template
        else:
            return False


VOLUME_TYPES = (VaultSecretVolume, SecretVolume, ItsVolume, TemplateVolume)
TYPE_MAPPING = {t.TYPE: t for t in VOLUME_TYPES}


def from_nanny_dict(d):
    volume_type_str = d.get('type', None)
    if volume_type_str not in TYPE_MAPPING:
        raise ValueError('Invalid instance_spec.volume.type {}'.format(volume_type_str))
    else:
        name = d['name']
        version = d.get('version', '')
        if volume_type_str == VaultSecretVolume.TYPE:
            return VaultSecretVolume(name, version=version, **d['vaultSecretVolume']['vaultSecret'])
        elif volume_type_str == SecretVolume.TYPE:
            return SecretVolume(name, version=version,
                                secretName=d['secretVolume']['secretName'], **d['secretVolume']['keychainSecret'])
        else:
            cls = TYPE_MAPPING[volume_type_str]
            return cls(name, version=version, **d[cls.PATH])
