# 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 types so that we can reference ListType in sphinx param declarations.
# We can't just use list, because sphinx gets confused by
# openstack.resource.Resource.list and openstack.resource2.Resource.list
import types  # noqa


class ClusteringCloudMixin:
    pass

    @property
    def _clustering_client(self):
        if 'clustering' not in self._raw_clients:
            clustering_client = self._get_versioned_client(
                'clustering', min_version=1, max_version='1.latest')
            self._raw_clients['clustering'] = clustering_client
        return self._raw_clients['clustering']

# NOTE(gtema): work on getting rid of direct API calls showed that this
# implementation never worked properly and tests in reality verifying wrong
# things. Unless someone is really interested in this piece of code this will
# be commented out and apparently dropped completely. This has no impact on the
# proxy layer.

#    def create_cluster(self, name, profile, config=None, desired_capacity=0,
#                       max_size=None, metadata=None, min_size=None,
#                       timeout=None):
#        profile = self.get_cluster_profile(profile)
#        profile_id = profile['id']
#        body = {
#            'desired_capacity': desired_capacity,
#            'name': name,
#            'profile_id': profile_id
#        }
#
#        if config is not None:
#            body['config'] = config
#
#        if max_size is not None:
#            body['max_size'] = max_size
#
#        if metadata is not None:
#            body['metadata'] = metadata
#
#        if min_size is not None:
#            body['min_size'] = min_size
#
#        if timeout is not None:
#            body['timeout'] = timeout
#
#        return self.clustering.create_cluster(**body)
#
#    def set_cluster_metadata(self, name_or_id, metadata):
#        cluster = self.get_cluster(name_or_id)
#        if not cluster:
#            raise exc.OpenStackCloudException(
#                'Invalid Cluster {cluster}'.format(cluster=name_or_id))
#        self.clustering.set_cluster_metadata(cluster, **metadata)
#
#    def get_cluster_by_id(self, cluster_id):
#        try:
#            return self.get_cluster(cluster_id)
#        except Exception:
#            return None
#
#    def get_cluster(self, name_or_id, filters=None):
#        return _utils._get_entity(
#            cloud=self, resource='cluster',
#            name_or_id=name_or_id, filters=filters)
#
#    def update_cluster(self, name_or_id, new_name=None,
#                       profile_name_or_id=None, config=None, metadata=None,
#                       timeout=None, profile_only=False):
#        old_cluster = self.get_cluster(name_or_id)
#        if old_cluster is None:
#            raise exc.OpenStackCloudException(
#                'Invalid Cluster {cluster}'.format(cluster=name_or_id))
#        cluster = {
#            'profile_only': profile_only
#        }
#
#        if config is not None:
#            cluster['config'] = config
#
#        if metadata is not None:
#            cluster['metadata'] = metadata
#
#        if profile_name_or_id is not None:
#            profile = self.get_cluster_profile(profile_name_or_id)
#            if profile is None:
#                raise exc.OpenStackCloudException(
#                    'Invalid Cluster Profile {profile}'.format(
#                        profile=profile_name_or_id))
#            cluster['profile_id'] = profile.id
#
#        if timeout is not None:
#            cluster['timeout'] = timeout
#
#        if new_name is not None:
#            cluster['name'] = new_name
#
#        return self.update_cluster(old_cluster, cluster)
#
#    def delete_cluster(self, name_or_id):
#        cluster = self.get_cluster(name_or_id)
#        if cluster is None:
#            self.log.debug("Cluster %s not found for deleting", name_or_id)
#            return False
#
#        for policy in self.list_policies_on_cluster(name_or_id):
#            detach_policy = self.get_cluster_policy_by_id(
#                policy['policy_id'])
#            self.detach_policy_from_cluster(cluster, detach_policy)
#
#        for receiver in self.list_cluster_receivers():
#            if cluster["id"] == receiver["cluster_id"]:
#                self.delete_cluster_receiver(receiver["id"], wait=True)
#
#        self.clustering.delete_cluster(cluster)
#
#        return True
#
#    def search_clusters(self, name_or_id=None, filters=None):
#        clusters = self.list_clusters()
#        return _utils._filter_list(clusters, name_or_id, filters)
#
#    def list_clusters(self):
#        return list(self.clustering.clusters())
#
#    def attach_policy_to_cluster(
#        self, name_or_id, policy_name_or_id, is_enabled
#    ):
#        cluster = self.get_cluster(name_or_id)
#        policy = self.get_cluster_policy(policy_name_or_id)
#        if cluster is None:
#            raise exc.OpenStackCloudException(
#                'Cluster {cluster} not found for attaching'.format(
#                    cluster=name_or_id))
#
#        if policy is None:
#            raise exc.OpenStackCloudException(
#                'Policy {policy} not found for attaching'.format(
#                    policy=policy_name_or_id))
#
#        self.clustering.attach_policy_to_cluster(cluster, policy)
#
#        return True
#
#    def detach_policy_from_cluster(
#            self, name_or_id, policy_name_or_id, wait=False, timeout=3600):
#        cluster = self.get_cluster(name_or_id)
#        policy = self.get_cluster_policy(policy_name_or_id)
#        if cluster is None:
#            raise exc.OpenStackCloudException(
#                'Cluster {cluster} not found for detaching'.format(
#                    cluster=name_or_id))
#
#        if policy is None:
#            raise exc.OpenStackCloudException(
#                'Policy {policy} not found for detaching'.format(
#                    policy=policy_name_or_id))
#
#        self.clustering.detach_policy_from_cluster(cluster, policy)
#
#        if not wait:
#            return True
#
#        for count in utils.iterate_timeout(
#                timeout, "Timeout waiting for cluster policy to detach"):
#
#            policies = self.get_cluster_by_id(cluster['id']).policies
#
#            # NOTE(gtema): we iterate over all current policies and "continue"
#            # if selected policy is still there
#            is_present = False
#            for active_policy in policies:
#                if active_policy.id == policy.id:
#                    is_present = True
#            if not is_present:
#                break
#        return True
#
#    def update_policy_on_cluster(self, name_or_id, policy_name_or_id,
#                                 is_enabled):
#        cluster = self.get_cluster(name_or_id)
#        policy = self.get_cluster_policy(policy_name_or_id)
#        if cluster is None:
#            raise exc.OpenStackCloudException(
#                'Cluster {cluster} not found for updating'.format(
#                    cluster=name_or_id))
#
#        if policy is None:
#            raise exc.OpenStackCloudException(
#                'Policy {policy} not found for updating'.format(
#                    policy=policy_name_or_id))
#
#        self.clustering.update_cluster_policy(
#            cluster, policy, is_enabled=is_enabled)
#
#        return True
#
#    def get_policy_on_cluster(self, name_or_id, policy_name_or_id):
#        cluster = self.get_cluster(name_or_id)
#        policy = self.get_policy(policy_name_or_id)
#        if policy and cluster:
#            return self.clustering.get_cluster_policy(
#            policy, cluster)
#        else:
#            return False
#
#    def list_policies_on_cluster(self, name_or_id):
#        cluster = self.get_cluster(name_or_id)
#        return list(self.clustering.cluster_policies(cluster))
#
#    def create_cluster_profile(self, name, spec, metadata=None):
#        profile = {
#            'name': name,
#            'spec': spec
#        }
#
#        if metadata is not None:
#            profile['metadata'] = metadata
#
#        data = self._clustering_client.post(
#            '/profiles', json={'profile': profile},
#            error_message="Error creating profile {name}".format(name=name))
#
#        return self._get_and_munchify('profile', data)
#
#    def set_cluster_profile_metadata(self, name_or_id, metadata):
#        profile = self.get_cluster_profile(name_or_id)
#        if not profile:
#            raise exc.OpenStackCloudException(
#                'Invalid Profile {profile}'.format(profile=name_or_id))
#
#        self._clustering_client.post(
#            '/profiles/{profile_id}/metadata'.format(profile_id=profile['id']),
#            json={'metadata': metadata},
#            error_message='Error updating profile metadata')
#
#    def search_cluster_profiles(self, name_or_id=None, filters=None):
#        cluster_profiles = self.list_cluster_profiles()
#        return _utils._filter_list(cluster_profiles, name_or_id, filters)
#
#    def list_cluster_profiles(self):
#        try:
#            data = self._clustering_client.get(
#                '/profiles',
#                error_message="Error fetching profiles")
#        except exc.OpenStackCloudURINotFound as e:
#            self.log.debug(str(e), exc_info=True)
#            return []
#        return self._get_and_munchify('profiles', data)
#
#    def get_cluster_profile_by_id(self, profile_id):
#        try:
#            data = self._clustering_client.get(
#                "/profiles/{profile_id}".format(profile_id=profile_id),
#                error_message="Error fetching profile {name}".format(
#                    name=profile_id))
#            return self._get_and_munchify('profile', data)
#        except exc.OpenStackCloudURINotFound as e:
#            self.log.debug(str(e), exc_info=True)
#            return None
#
#    def get_cluster_profile(self, name_or_id, filters=None):
#        return _utils._get_entity(self, 'cluster_profile', name_or_id,
#                                  filters)
#
#    def delete_cluster_profile(self, name_or_id):
#        profile = self.get_cluster_profile(name_or_id)
#        if profile is None:
#            self.log.debug("Profile %s not found for deleting", name_or_id)
#            return False
#
#        for cluster in self.list_clusters():
#            if (name_or_id, profile.id) in cluster.items():
#                self.log.debug(
#                    "Profile %s is being used by cluster %s, won't delete",
#                    name_or_id, cluster.name)
#                return False
#
#        self._clustering_client.delete(
#            "/profiles/{profile_id}".format(profile_id=profile['id']),
#            error_message="Error deleting profile "
#                          "{name}".format(name=name_or_id))
#
#        return True
#
#    def update_cluster_profile(
#        self, name_or_id, metadata=None, new_name=None
#    ):
#        old_profile = self.get_cluster_profile(name_or_id)
#        if not old_profile:
#            raise exc.OpenStackCloudException(
#                'Invalid Profile {profile}'.format(profile=name_or_id))
#
#        profile = {}
#
#        if metadata is not None:
#            profile['metadata'] = metadata
#
#        if new_name is not None:
#            profile['name'] = new_name
#
#        data = self._clustering_client.patch(
#            "/profiles/{profile_id}".format(profile_id=old_profile.id),
#            json={'profile': profile},
#            error_message="Error updating profile {name}".format(
#                name=name_or_id))
#
#        return self._get_and_munchify(key=None, data=data)
#
#    def create_cluster_policy(self, name, spec):
#        policy = {
#            'name': name,
#            'spec': spec
#        }
#
#        data = self._clustering_client.post(
#            '/policies', json={'policy': policy},
#            error_message="Error creating policy {name}".format(
#                name=policy['name']))
#        return self._get_and_munchify('policy', data)
#
#    def search_cluster_policies(self, name_or_id=None, filters=None):
#        cluster_policies = self.list_cluster_policies()
#        return _utils._filter_list(cluster_policies, name_or_id, filters)
#
#    def list_cluster_policies(self):
#        endpoint = "/policies"
#        try:
#            data = self._clustering_client.get(
#                endpoint,
#                error_message="Error fetching cluster policies")
#        except exc.OpenStackCloudURINotFound as e:
#            self.log.debug(str(e), exc_info=True)
#            return []
#        return self._get_and_munchify('policies', data)
#
#    def get_cluster_policy_by_id(self, policy_id):
#        try:
#            data = self._clustering_client.get(
#                "/policies/{policy_id}".format(policy_id=policy_id),
#                error_message="Error fetching policy {name}".format(
#                    name=policy_id))
#            return self._get_and_munchify('policy', data)
#        except exc.OpenStackCloudURINotFound as e:
#            self.log.debug(str(e), exc_info=True)
#            return None
#
#    def get_cluster_policy(self, name_or_id, filters=None):
#        return _utils._get_entity(
#            self, 'cluster_policie', name_or_id, filters)
#
#    def delete_cluster_policy(self, name_or_id):
#        policy = self.get_cluster_policy_by_id(name_or_id)
#        if policy is None:
#            self.log.debug("Policy %s not found for deleting", name_or_id)
#            return False
#
#        for cluster in self.list_clusters():
#            if (name_or_id, policy.id) in cluster.items():
#                self.log.debug(
#                    "Policy %s is being used by cluster %s, won't delete",
#                    name_or_id, cluster.name)
#                return False
#
#        self._clustering_client.delete(
#            "/policies/{policy_id}".format(policy_id=name_or_id),
#            error_message="Error deleting policy "
#                          "{name}".format(name=name_or_id))
#
#        return True
#
#    def update_cluster_policy(self, name_or_id, new_name):
#        old_policy = self.get_cluster_policy(name_or_id)
#        if not old_policy:
#            raise exc.OpenStackCloudException(
#                'Invalid Policy {policy}'.format(policy=name_or_id))
#        policy = {'name': new_name}
#
#        data = self._clustering_client.patch(
#            "/policies/{policy_id}".format(policy_id=old_policy.id),
#            json={'policy': policy},
#            error_message="Error updating policy "
#                          "{name}".format(name=name_or_id))
#        return self._get_and_munchify(key=None, data=data)
#
#    def create_cluster_receiver(self, name, receiver_type,
#                                cluster_name_or_id=None, action=None,
#                                actor=None, params=None):
#        cluster = self.get_cluster(cluster_name_or_id)
#        if cluster is None:
#            raise exc.OpenStackCloudException(
#                'Invalid cluster {cluster}'.format(
#                    cluster=cluster_name_or_id))
#
#        receiver = {
#            'name': name,
#            'type': receiver_type
#        }
#
#        if cluster_name_or_id is not None:
#            receiver['cluster_id'] = cluster.id
#
#        if action is not None:
#            receiver['action'] = action
#
#        if actor is not None:
#            receiver['actor'] = actor
#
#        if params is not None:
#            receiver['params'] = params
#
#        data = self._clustering_client.post(
#            '/receivers', json={'receiver': receiver},
#            error_message="Error creating receiver {name}".format(name=name))
#        return self._get_and_munchify('receiver', data)
#
#    def search_cluster_receivers(self, name_or_id=None, filters=None):
#        cluster_receivers = self.list_cluster_receivers()
#        return _utils._filter_list(cluster_receivers, name_or_id, filters)
#
#    def list_cluster_receivers(self):
#        try:
#            data = self._clustering_client.get(
#                '/receivers',
#                error_message="Error fetching receivers")
#        except exc.OpenStackCloudURINotFound as e:
#            self.log.debug(str(e), exc_info=True)
#            return []
#        return self._get_and_munchify('receivers', data)
#
#    def get_cluster_receiver_by_id(self, receiver_id):
#        try:
#            data = self._clustering_client.get(
#                "/receivers/{receiver_id}".format(receiver_id=receiver_id),
#                error_message="Error fetching receiver {name}".format(
#                    name=receiver_id))
#            return self._get_and_munchify('receiver', data)
#        except exc.OpenStackCloudURINotFound as e:
#            self.log.debug(str(e), exc_info=True)
#            return None
#
#    def get_cluster_receiver(self, name_or_id, filters=None):
#        return _utils._get_entity(
#            self, 'cluster_receiver', name_or_id, filters)
#
#    def delete_cluster_receiver(self, name_or_id, wait=False, timeout=3600):
#        receiver = self.get_cluster_receiver(name_or_id)
#        if receiver is None:
#            self.log.debug("Receiver %s not found for deleting", name_or_id)
#            return False
#
#        receiver_id = receiver['id']
#
#        self._clustering_client.delete(
#            "/receivers/{receiver_id}".format(receiver_id=receiver_id),
#            error_message="Error deleting receiver {name}".format(
#                name=name_or_id))
#
#        if not wait:
#            return True
#
#        for count in utils.iterate_timeout(
#                timeout, "Timeout waiting for cluster receiver to delete"):
#
#            receiver = self.get_cluster_receiver_by_id(receiver_id)
#
#            if not receiver:
#                break
#
#        return True
#
#    def update_cluster_receiver(self, name_or_id, new_name=None, action=None,
#                                params=None):
#        old_receiver = self.get_cluster_receiver(name_or_id)
#        if old_receiver is None:
#            raise exc.OpenStackCloudException(
#                'Invalid receiver {receiver}'.format(receiver=name_or_id))
#
#        receiver = {}
#
#        if new_name is not None:
#            receiver['name'] = new_name
#
#        if action is not None:
#            receiver['action'] = action
#
#        if params is not None:
#            receiver['params'] = params
#
#        data = self._clustering_client.patch(
#            "/receivers/{receiver_id}".format(receiver_id=old_receiver.id),
#            json={'receiver': receiver},
#            error_message="Error updating receiver {name}".format(
#                name=name_or_id))
#        return self._get_and_munchify(key=None, data=data)
