# Copyright 2016 AT&T Corp
# All Rights Reserved.
#
#    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 random

import time

from ranger_tempest_plugin.tests.api import base

from oslo_log import log as logging

from tempest import config

from tempest.lib import exceptions

CONF = config.CONF
LOG = logging.getLogger(__name__)


class FmsBaseOrmTest(base.BaseOrmTest):
    credentials = ['admin', 'primary', 'alt']

    # added setup_clients function by stew
    @classmethod
    def setup_clients(cls):
        super(FmsBaseOrmTest, cls).setup_clients()
        cls.client = cls.os_primary.fms_client
        cls.flavors_client = cls.os_admin.flavors_client
        cls.tenant_id = cls._get_project_id(
            cls.os_primary.credentials.project_name)
        cls.alt_tenant_id = cls._get_project_id(
            cls.os_alt.credentials.project_name)

    @classmethod
    def _get_flavor_params(cls, set_region=True, single_tenant=True):
        post_body, region = {}, {}
        region["name"] = CONF.identity.region
        ram = random.randint(1, 4) * 1024
        swap = random.randint(1, 40) * 1024
        vcpus = random.randint(2, 40)
        disk = random.randint(2, 102)
        post_body["description"] = \
            "orm-plugin-BaseORMTest-flavor"
        post_body["series"] = random.choice(CONF.ranger.flavor_series)
        post_body["alias"] = "flavor_alias"
        post_body["ram"] = str(ram)
        post_body["vcpus"] = str(vcpus)
        post_body["disk"] = str(disk)
        post_body["swap"] = str(swap)
        post_body["ephemeral"] = "1024"
        post_body["regions"] = [region] if set_region else []
        post_body["visibility"] = "private"
        post_body['tag'] = {'a': 'b', 'c': 'd'}

        if single_tenant:
            post_body["tenants"] = [cls.tenant_id]
        else:
            post_body["tenants"] = [cls.tenant_id, cls.alt_tenant_id]
        return post_body

    @classmethod
    def _create_flv_and_validate_creation_on_dcp_and_lcp(cls, **kwargs):
        """ kwargs contain all field data needed in a flavor POST body:
        - name
        - description
        - alias
        - ram
        - vcpus
        - disk
        - swap
        - ephemeral
        - regions
        - visibility
        - tenants
        """
        _, body = cls.client.create_flavor(**kwargs)
        flavor = body["flavor"]
        flavor_id = flavor["id"]
        _, body = cls.client.get_flavor(flavor_id)
        flavor_detail = body["flavor"]
        if flavor_detail["vcpus"] == kwargs["vcpus"]:
            if flavor_detail["regions"] == []:
                flavor_status = "no regions"
            else:
                flavor_status = "Success"
            flavor_id = flavor_detail["id"]
            cls._wait_for_flavor_status_on_dcp(flavor_id, flavor_status)
            cls._validate_flavor_creation_on_lcp(flavor_id)
            return flavor
        else:
            message = "flavor %s not created successfully" % flavor_id
            raise exceptions.TempestException(message)

    @classmethod
    def _wait_for_flavor_status_on_dcp(cls, flavor_id, status):
        _, body = cls.client.get_flavor(flavor_id)
        flavor = body["flavor"]
        flavor_status = flavor["status"]
        start = int(time.time())
        while flavor_status != status:
            time.sleep(cls.build_interval)
            _, body = cls.client.get_flavor(flavor_id)
            flavor = body["flavor"]
            flavor_status = flavor["status"]
            if flavor_status == 'Error':
                message = ('flavor %s failed to reach %s status'
                           ' and is in ERROR status' %
                           (flavor_id, status))
                raise exceptions.TempestException(message)
            if int(time.time()) - start >= cls.build_timeout:
                message =\
                    'flavor %s failed to reach %s status within'
                ' the required time (%s s) and is in'
                '%s status.' % (flavor_id, status,
                                cls.build_timeout, flavor_status)
                raise exceptions.TimeoutException(message)

    @classmethod
    def _validate_flavor_creation_on_lcp(cls, flavor_id):
        _, body = cls.client.list_flavors()
        flavor = [flavor["id"] for flavor in body["flavors"]
                  if flavor["id"] == flavor_id]
        if not flavor:
            message = "flavor %s not in nova flavor list" % flavor_id
            raise exceptions.TempestException(message)

    @classmethod
    def _validate_flv_extraspecs_on_dcp_and_lcp(cls, flavor_id,
                                                expected_specs):
        expected_specs_count = len(expected_specs)
        _, body = cls.client.get_flavor(flavor_id)
        flavor_orm = body["flavor"]
        flavor_lcp = cls.flavors_client.show_flavor(flavor_id)["flavor"]

        def _validate_extra_specs(flv):
            actual_specs_count = 0
            actual_specs = {}
            for spec in flv["extra-specs"]:
                actual_specs[spec] = flv["extra-specs"][spec]
            for spec in expected_specs:
                if spec in actual_specs:
                    if expected_specs[spec] == actual_specs[spec]:
                        actual_specs_count += 1
            if expected_specs_count == actual_specs_count:
                return True
            else:
                return False
        if _validate_extra_specs(flavor_orm) and\
                _validate_extra_specs(flavor_lcp):
            return True
        else:
            return False

    @classmethod
    def _del_flv_and_validate_deletion_on_dcp_and_lcp(cls, flavor_id):
        _, body = cls.client.get_flavor(flavor_id)
        regions_on_flavor = [region for region in body["flavor"]["regions"]]

        if regions_on_flavor:
            region_name_on_flavor = regions_on_flavor[0]["name"]
            cls._delete_region_from_flavor_and_validate_deletion(
                flavor_id, region_name_on_flavor)
        cls.client.delete_flavor(flavor_id)
        cls._wait_for_flavor_deletion_on_dcp(flavor_id)
        cls._validate_flavor_deletion_on_lcp(flavor_id)

    @classmethod
    def _delete_region_from_flavor_and_validate_deletion(
            cls, flavor_id, rname):
        _, body = cls.rms_client.get_region(rname)
        region_id = body["id"]
        cls.client.delete_region_from_flavor(flavor_id, region_id)
        cls._wait_for_flavor_status_on_dcp(flavor_id, "no regions")
        _, body = cls.client.get_flavor(flavor_id)
        regions_on_flavor = body["flavor"]["regions"]

        if regions_on_flavor:
            message = \
                "Region %s failed to get deleted from flavor %s " % (
                    rname, flavor_id)
            raise exceptions.TempestException(message)
        cls._validate_flavor_deletion_on_lcp(flavor_id)

    @classmethod
    def _wait_for_flavor_deletion_on_dcp(cls, flavor_id):
        _, body = cls.client.list_flavors()
        flavor_ids = [flavor["id"] for flavor in body["flavors"]
                      if flavor["id"] == flavor_id]
        start = int(time.time())
        while flavor_ids:
            time.sleep(cls.build_interval)
            _, body = cls.client.list_flavors()
            flavor_ids = [flavor["id"] for flavor in body["flavors"]
                          if flavor["id"] == flavor_id]
            if flavor_ids:
                flavor_status = flavor_ids[0]["status"]
                if flavor_status == 'Error':
                    message = \
                        'Flavor %s failed to get deleted'
                    'and is in error status' % \
                        flavor_id
                    raise exceptions.TempestException(message)
            if int(time.time()) - start >= cls.build_timeout:
                message = (
                    'flavor %s failed to get deleted within '
                    'the required time (%s s) and is in %s status.'
                    % (flavor_id, cls.build_timeout, flavor_status))
                raise exceptions.TimeoutException(message)

    @classmethod
    def _validate_flavor_deletion_on_lcp(cls, flavor_id):
        body = cls.flavors_client.list_flavors()["flavors"]
        flavor_ids = [flavor["id"] for flavor in body
                      if flavor["id"] == flavor_id]
        if flavor_ids:
            flavor_status = cls.flavors_client.show_flavor(
                flavor_id)["flavor"]["status"]
            message = "flavor %s failed to get deleted and is in %s status" \
                      % (flavor_id, flavor_status)
            raise exceptions.TempestException(message)

    @classmethod
    def _get_project_id(cls, project_name):
        body = cls.identity_client.list_projects()
        for project in body["projects"]:
            if(project["name"] == project_name):
                return project["id"]
        message = ('project %s not found on projects list' % project_name)
        raise exceptions.TempestException(message)

    @classmethod
    def _get_expected_flavor_name(cls, post_body):
        name = post_body["series"] + "." + "c" + \
            post_body["vcpus"] + "r" + \
            str(int(post_body["ram"]) / 1024) \
            + "d" + post_body["disk"] + "s" + \
            str(int(post_body["swap"]) / 1024) \
            + "e" + str(int(post_body["ephemeral"]) / 1024)
        return name

    @classmethod
    def _validate_flv_geometry_on_lcp(cls, flavor_id, post_body):
        flv = cls.flavors_client.show_flavor(flavor_id)["flavor"]
        if flv["vcpus"] == int(post_body["vcpus"]) and \
                flv["ram"] == post_body["ram"] and \
                flv["swap"] == int(post_body["swap"]) and \
                flv["disk"] == int(post_body["disk"]) and \
                flv["ephemeral"] == post_body["ephemeral"]:
            return True
        else:
            return False
