# -*- coding: utf8 -*-
#
#    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 collections
import json
import logging


from django.conf import settings
from django.utils.translation import ugettext_lazy as _
import horizon.messages
from horizon import tabs
import requests
import requests_oauthlib
from tuskar_ui import api
from tuskar_ui.infrastructure.nodes import tabs as nodes_tabs

from tuskar_sat_ui.nodes import tables


SAT_HOST_PARAM = 'SatelliteHost'
SAT_AUTH_PARAM = 'SatelliteAuth'
SAT_ORG_PARAM = 'SatelliteOrg'
VERIFY_SSL = not getattr(settings, 'OPENSTACK_SSL_NO_VERIFY', False)
LOG = logging.getLogger('tuskar_sat_ui')
ErrataItem = collections.namedtuple('ErrataItem', [
    'title',
    'type',
    'id',
    'issued',
])


class Error(Exception):
    pass


class NoConfigError(Error):
    """Failed to find the Satellite configuration in Heat parameters."""

    def __init__(self, param=None, *args, **kwargs):
        super(NoConfigError, self).__init__(*args, **kwargs)
        self.param = param


class NodeNotFound(Error):
    """Failed to find the Satellite node."""


class BadAuthError(Error):
    """Unknown authentication method for Satellite."""

    def __init__(self, auth=None, *args, **kwargs):
        super(BadAuthError, self).__init__(*args, **kwargs)
        self.auth = auth


class NoErrataError(Error):
    """There is no errata for that node."""


def _get_satellite_config(parameters):
    """Find the Satellite configuration data.

    The configuration data is store in Heat as parameters.  They may be
    stored directly as Heat parameters, or in a the JSON structure stored
    in ExtraConfig.
    """

    param = 'Satellite'
    try:
        config = parameters[param]
    except KeyError:
        try:
            extra = json.loads(parameters['compute-1::ExtraConfig'])
            config = extra[param]
        except (KeyError, ValueError, TypeError):
            raise NoConfigError(param, 'Parameter %r missing.' % param)

    for param in [SAT_HOST_PARAM, SAT_AUTH_PARAM, SAT_ORG_PARAM]:
        if param not in config:
            raise NoConfigError(param, 'Parameter %r missing.' % param)

    host = config[SAT_HOST_PARAM]
    host = host.strip('/')  # Get rid of any trailing slash in the host url

    try:
        auth = config[SAT_AUTH_PARAM].split(':', 2)
    except ValueError:
        raise BadAuthError(auth=config[SAT_AUTH_PARAM])
    if auth[0] == 'oauth':
        auth = requests_oauthlib.OAuth1(auth[1], auth[2])
    elif auth[0] == 'basic':
        auth = auth[1], auth[2]
    else:
        raise BadAuthError(auth=auth[0])
    organization = config[SAT_ORG_PARAM]
    return host, auth, organization


def _get_stack(request):
    """Find the stack."""

    # TODO(rdopiera) We probably should use the StackMixin instead.
    try:
        plan = api.tuskar.Plan.get_the_plan(request)
        stack = api.heat.Stack.get_by_plan(request, plan)
    except Exception as e:
        LOG.exception(e)
        horizon.messages.error(request, _("Could not retrieve errata."))
        return None
    return stack


def _find_uuid_by_mac(host, auth, organization, addresses):
    """Pick up the UUID from the MAC address.

    This makes no sense, as we need both MAC address and the interface, and
    we don't have the interface, so we need to make multiple slow searches.
    If the Satellite UUID isn't the same as this one, and it probably
    isn't, we need to store a mapping somewhere.
    """

    url = '{host}/katello/api/v2/systems'.format(host=host)
    for mac in addresses:
        for interface in ['eth0', 'eth1', 'en0', 'en1']:
            q = 'facts.net.interface.{iface}.mac_address:{mac}'.format(
                iface=interface, mac=mac)
            params = {'search': q, 'organization_id': organization}
            r = requests.get(url, params=params, auth=auth,
                             verify=VERIFY_SSL)
            r.raise_for_status()  # Raise an error if the request failed
            contexts = r.json()['results']
            if contexts:
                return contexts[0]['uuid']
    raise NodeNotFound()


def _get_errata_data(self, host, auth, uuid):
    """Get the errata here, while it's hot."""

    url = '{host}/katello/api/v2/systems/{id}/errata'.format(host=host,
                                                             id=uuid)
    r = requests.get(url, auth=auth, verify=VERIFY_SSL)
    r.raise_for_status()  # Raise an error if the request failed
    errata = r.json()['contexts']
    if not errata:
        raise NoErrataError()
    data = [ErrataItem(x['title'], x['type'], x['id'], x['issued'])
            for x in errata]
    return data


class DetailOverviewTab(nodes_tabs.DetailOverviewTab):
    template_name = 'infrastructure/nodes/_detail_overview_sat.html'

    def get_context_data(self, request, **kwargs):
        context = super(DetailOverviewTab,
                        self).get_context_data(request, **kwargs)
        if context['node'].uuid is None:
            return context

        # TODO(rdopiera) We can probably get the stack from the context.
        stack = _get_stack(request)
        if stack is None:
            return context

        try:
            host, auth, organization = _get_satellite_config(stack.parameters)
        except NoConfigError as e:
            horizon.messages.error(request, _(
                "No Satellite configuration found. "
                "Missing parameter %r."
            ) % e.param)
            return context
        except BadAuthError as e:
            horizon.messages.error(request, _(
                "Satellite configuration error, "
                "unknown authentication method %r."
            ) % e.auth)
            return context

        addresses = context['node'].addresses
        try:
            uuid = _find_uuid_by_mac(host, auth, organization, addresses)
        except NodeNotFound:
            return context

        # TODO(rdopiera) Should probably catch that requests exception here.
        try:
            data = self._get_errata_data(host, auth, uuid)
        except NoErrataError:
            return context
        context['errata'] = tables.ErrataTable(request, data=data)
        return context


class NodeDetailTabs(tabs.TabGroup):
    slug = "node_details"
    tabs = (DetailOverviewTab,)

@@ -4653,22 +4653,16 @@
 ta_data(
-self, 
 host, au
@@ -6551,21 +6551,16 @@
  data = 
-self.
 _get_err

Fix call of _get_errata_data