# Copyright 2016 Capital One Services, LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import itertools

from c7n.query import QueryResourceManager
from c7n.manager import resources
from c7n.utils import local_session, chunks


@resources.register('health-event')
class HealthEvents(QueryResourceManager):
    """Query resource manager for AWS health events
    """

    class resource_type(object):
        service = 'health'
        type = 'event'
        enum_spec = ('describe_events', 'events', None)
        name = 'eventTypeCode'
        id = 'arn'
        filter_name = None
        filter_type = None
        dimension = None
        date = 'startTime'

    permissions = (
        'health:DescribeEvents',
        'health:DescribeEventDetails',
        'health:DescribeAffectedEntities')

    def __init__(self, ctx, data):
        if ctx.options.region != 'us-east-1':
            raise ValueError(
                'resource:health-event is only available in us-east-1')
        super(HealthEvents, self).__init__(ctx, data)
        self.queries = QueryFilter.parse(
            self.data.get('query', [
                {'eventStatusCodes': 'open'},
                {'eventTypeCategories': ['issue', 'accountNotification']}]))

    def resource_query(self):
        qf = {}
        for q in self.queries:
            qd = q.query()
            if qd['Name'] in qf:
                for qv in qf[qd['Name']]:
                    if qv in qf[qd['Name']]:
                        continue
                    qf[qd['Name']].append(qv)
            else:
                qf[qd['Name']] = []
                for qv in qd['Values']:
                    qf[qd['Name']].append(qv)
        return qf

    def resources(self, query=None):
        q = self.resource_query()
        if q is not None:
            query = query or {}
            query['filter'] = q
        return super(HealthEvents, self).resources(query=query)

    def augment(self, resources):
        client = local_session(self.session_factory).client('health')
        for resource_set in chunks(resources, 10):
            event_map = {r['arn']: r for r in resource_set}
            event_details = client.describe_event_details(
                eventArns=event_map.keys())['successfulSet']
            for d in event_details:
                event_map[d['event']['arn']][
                    'Description'] = d['eventDescription']['latestDescription']

            event_arns = [r['arn'] for r in resource_set
                          if r['eventTypeCategory'] != 'accountNotification']

            if not event_arns:
                continue
            paginator = client.get_paginator('describe_affected_entities')
            entities = list(itertools.chain(
                *[p['entities']for p in paginator.paginate(
                    filter={'eventArns': event_arns})]))

            for e in entities:
                event_map[e.pop('eventArn')].setdefault(
                    'AffectedEntities', []).append(e)

        return resources


HEALTH_VALID_FILTERS = {
    'availability-zone': str,
    'eventTypeCategories': {'issue', 'accountNotification', 'scheduledChange'},
    'regions': str,
    'services': str,
    'eventStatusCodes': {'open', 'closed', 'upcoming'},
    'eventTypeCodes': str
}


class QueryFilter(object):

    @classmethod
    def parse(cls, data):
        results = []
        for d in data:
            if not isinstance(d, dict):
                raise ValueError(
                    "Health Query Filter Invalid structure %s" % d)
            results.append(cls(d).validate())
        return results

    def __init__(self, data):
        self.data = data
        self.key = None
        self.value = None

    def validate(self):
        if not len(self.data.keys()) == 1:
            raise ValueError(
                "Health Query Filter Invalid %s" % self.data)
        self.key = self.data.keys()[0]
        self.value = self.data.values()[0]

        if self.key not in HEALTH_VALID_FILTERS:
            raise ValueError(
                "Health Query Filter invalid filter name %s" % (self.data))

        if self.value is None:
            raise ValueError(
                "Health Query Filters must have a value, use tag-key"
                " w/ tag name as value for tag present checks"
                " %s" % self.data)
        return self

    def query(self):
        value = self.value
        if isinstance(self.value, basestring):
            value = [self.value]
        return {'Name': self.key, 'Values': value}
