# Copyright 2013 Hewlett-Packard, Ltd.
#
#    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 re
import string
import unicodedata

from oslo_serialization import jsonutils as json
from tempest_lib.common.utils import misc
import testscenarios
import testtools

from tempest import clients
from tempest.common import credentials
from tempest import config
from tempest import exceptions

CONF = config.CONF


class ImageUtils(object):

    default_ssh_user = 'root'

    def __init__(self, os):
        # Load configuration items
        self.ssh_users = json.loads(CONF.input_scenario.ssh_user_regex)
        self.non_ssh_image_pattern = \
            CONF.input_scenario.non_ssh_image_regex
        # Setup clients
        self.images_client = os.images_client
        self.flavors_client = os.flavors_client

    def ssh_user(self, image_id):
        _image = self.images_client.show_image(image_id)
        for regex, user in self.ssh_users:
            # First match wins
            if re.match(regex, _image['name']) is not None:
                return user
        else:
            return self.default_ssh_user

    def _is_sshable_image(self, image):
        return not re.search(pattern=self.non_ssh_image_pattern,
                             string=str(image['name']))

    def is_sshable_image(self, image_id):
        _image = self.images_client.show_image(image_id)
        return self._is_sshable_image(_image)

    def _is_flavor_enough(self, flavor, image):
        return image['minDisk'] <= flavor['disk']

    def is_flavor_enough(self, flavor_id, image_id):
        _image = self.images_client.show_image(image_id)
        _flavor = self.flavors_client.show_flavor(flavor_id)['flavor']
        return self._is_flavor_enough(_flavor, _image)


@misc.singleton
class InputScenarioUtils(object):

    """
    Example usage:

    import testscenarios
    (...)
    load_tests = testscenarios.load_tests_apply_scenarios


    class TestInputScenario(manager.ScenarioTest):

        scenario_utils = utils.InputScenarioUtils()
        scenario_flavor = scenario_utils.scenario_flavors
        scenario_image = scenario_utils.scenario_images
        scenarios = testscenarios.multiply_scenarios(scenario_image,
                                                     scenario_flavor)

        def test_create_server_metadata(self):
            name = rand_name('instance')
            self.servers_client.create_server(name=name,
                                              flavor_ref=self.flavor_ref,
                                              image_ref=self.image_ref)
    """
    validchars = "-_.{ascii}{digit}".format(ascii=string.ascii_letters,
                                            digit=string.digits)

    def __init__(self):
        network_resources = {
            'network': False,
            'router': False,
            'subnet': False,
            'dhcp': False,
        }
        self.isolated_creds = credentials.get_isolated_credentials(
            name='InputScenarioUtils',
            identity_version=CONF.identity.auth_version,
            network_resources=network_resources)
        os = clients.Manager(self.isolated_creds.get_primary_creds())
        self.images_client = os.images_client
        self.flavors_client = os.flavors_client
        self.image_pattern = CONF.input_scenario.image_regex
        self.flavor_pattern = CONF.input_scenario.flavor_regex

    def _normalize_name(self, name):
        nname = unicodedata.normalize('NFKD', name).encode('ASCII', 'ignore')
        nname = ''.join(c for c in nname if c in self.validchars)
        return nname

    def clear_creds(self):
        self.isolated_creds.clear_isolated_creds()

    @property
    def scenario_images(self):
        """
        :return: a scenario with name and uuid of images
        """
        if not CONF.service_available.glance:
            return []
        if not hasattr(self, '_scenario_images'):
            try:
                images = self.images_client.list_images()
                self._scenario_images = [
                    (self._normalize_name(i['name']), dict(image_ref=i['id']))
                    for i in images if re.search(self.image_pattern,
                                                 str(i['name']))
                ]
            except Exception:
                self._scenario_images = []
        return self._scenario_images

    @property
    def scenario_flavors(self):
        """
        :return: a scenario with name and uuid of flavors
        """
        if not hasattr(self, '_scenario_flavors'):
            try:
                flavors = self.flavors_client.list_flavors()['flavors']
                self._scenario_flavors = [
                    (self._normalize_name(f['name']), dict(flavor_ref=f['id']))
                    for f in flavors if re.search(self.flavor_pattern,
                                                  str(f['name']))
                ]
            except Exception:
                self._scenario_flavors = []
        return self._scenario_flavors


def load_tests_input_scenario_utils(*args):
    """
    Wrapper for testscenarios to set the scenarios to avoid running a getattr
    on the CONF object at import.
    """
    if getattr(args[0], 'suiteClass', None) is not None:
        loader, standard_tests, pattern = args
    else:
        standard_tests, module, loader = args
    output = None
    scenario_utils = None
    try:
        scenario_utils = InputScenarioUtils()
        scenario_flavor = scenario_utils.scenario_flavors
        scenario_image = scenario_utils.scenario_images
    except (exceptions.InvalidConfiguration, TypeError):
        output = standard_tests
    finally:
        if scenario_utils:
            scenario_utils.clear_creds()
    if output is not None:
        return output
    for test in testtools.iterate_tests(standard_tests):
        setattr(test, 'scenarios', testscenarios.multiply_scenarios(
            scenario_image,
            scenario_flavor))
    return testscenarios.load_tests_apply_scenarios(*args)
