# coding: utf-8

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

import re
import six
import logging

from cached_property import cached_property

from .tag import GencfgTag
from .api import GencfgAPI
from .errors import GencfgGroupNotFound, GencfgApiError

GENCFG_GROUPS_LOCATIONS = frozenset({'SAS', 'MAN', 'VLA', 'IVA'})


class GencfgGroup(object):
    LOGGER = logging.getLogger(__name__)
    REGEXP_IO_LIMIT = re.compile('^(hdd|ssd)_io(_ops)?_(read|write)_limit$')
    REGEXP_GROUP_GEO = re.compile('(.+_)?(?P<location>{})(_.+)?'.format('|'.join(GENCFG_GROUPS_LOCATIONS)))

    def __init__(self, name, tag=None, validate=True):
        self._name = name
        self._tag = GencfgTag(tag)
        self._gencfg_api = GencfgAPI(tag=self._tag)
        if validate and not self._gencfg_api.group_exists(self._name):
            raise GencfgGroupNotFound(group=name, tag=tag)

    @classmethod
    def from_str(cls, name_with_tag):
        parts = name_with_tag.split(':')
        if len(parts) == 1:
            return cls(parts[0])
        elif len(parts) == 2:
            return cls(parts[0], parts[1])
        else:
            raise ValueError('Not valid group specification "{}"'.format(name_with_tag))

    @classmethod
    def list_from_str(cls, names_with_tags):
        result = []
        for name_with_tag in names_with_tags.split(','):
            result.append(cls.from_str(name_with_tag))
        return result

    @property
    def name(self):
        return self._name

    @property
    def tag(self):
        return self._tag

    @tag.setter
    def tag(self, value):
        self._tag = GencfgTag(value)
        self._gencfg_api.tag = self._tag
        # invalidate cached property
        try:
            del self.__dict__['card']
        except KeyError:
            pass

    @cached_property
    def card(self):
        return self._gencfg_api.get_group_info_card(self.name)

    @property
    def io_limits(self):
        return {k: v for k, v in six.iteritems(self.card['reqs']['instances']) if self.REGEXP_IO_LIMIT.match(k) and v > 0}

    def __eq__(self, other):
        if isinstance(other, GencfgGroup):
            return self._name == other._name and self._tag == other._tag
        else:
            return NotImplemented

    def __ne__(self, other):
        return not self.__eq__(other)

    def __hash__(self):
        return hash((self._name, self._tag))

    def __repr__(self):
        return 'GencfgGroup(\'{}:{}\')'.format(self.name, self.tag)

    def __str__(self):
        return self.name

    @cached_property
    def prj_tags(self):
        return self.card['tags']['prj']

    @cached_property
    def location(self):
        try:
            locations_from_card = self.card['reqs']['hosts']['location']['location']
            if len(locations_from_card) == 1:
                return locations_from_card[0].upper()
            elif len(locations_from_card) > 1:
                raise GencfgApiError(None, 'Multiple locations for group {} in Gencfg response: {}'.format(self.name, locations_from_card))
        except KeyError:
            pass

        self.LOGGER.warning('Can\'t get %s location from card. Fallback to regexp guessing')
        re_match = self.REGEXP_GROUP_GEO.match(self.name)
        if re_match:
            return re_match.group('location')
        else:
            raise GencfgApiError(None, 'No locations in card for group {}, can\'t parse location from name'.format(self.name))

    @cached_property
    def hosts(self):
        return self._gencfg_api.get_group_hostlist(self.name)
