# Copyright 2026 Red Hat, Inc.
#
# 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.
#


"""Utilities for Watcher tests of code from the common module."""

from openstack.block_storage.v3 import service as block_service
from openstack.block_storage.v3 import snapshot as block_snapshot
from openstack.block_storage.v3 import stats
from openstack.block_storage.v3 import type as block_type
from openstack.block_storage.v3 import volume as block_volume
from openstack.compute.v2 import aggregate
from openstack.compute.v2 import flavor
from openstack.compute.v2 import hypervisor
from openstack.compute.v2 import server
from openstack.compute.v2 import server_migration
from openstack.compute.v2 import service
from openstack.placement.v1 import resource_provider_inventory


class NovaResourcesMixin:
    def create_openstacksdk_server(self, **kwargs):
        """Create a real OpenStackSDK Server object.

        :param kwargs: server attributes
        :returns: openstack.compute.v2.server.Server object
        """
        server_info = {
            'id': kwargs.pop('id', 'd010ef1f-dc19-4982-9383-087498bfde03'),
            'name': kwargs.pop('name', 'test-server'),
            'created_at': kwargs.pop('created_at', '2026-01-09T12:00:00Z'),
            'compute_host': kwargs.pop('compute_host', 'host0'),
            'vm_state': kwargs.pop('vm_state', None),
            'task_state': kwargs.pop('task_state', None),
            'power_state': kwargs.pop('power_state', None),
            'status': kwargs.pop('status', 'ACTIVE'),
            'flavor': kwargs.pop('flavor', {'id': 'flavor-1'}),
            'project_id': kwargs.pop('project_id', 'test-tenant-id'),
            'is_locked': kwargs.pop('is_locked', False),
            'metadata': kwargs.pop('metadata', {}),
            'availability_zone': kwargs.pop('availability_zone', None),
            'pinned_availability_zone': kwargs.pop(
                'pinned_availability_zone', None
            ),
            'image': kwargs.pop(
                'image', {'id': '155d900f-4e14-4e4c-a73d-069cbf4541e6'}
            ),
            'hypervisor_hostname': kwargs.pop('hypervisor_hostname', 'host0'),
        }
        server_info.update(kwargs)
        return server.Server(**server_info)

    def create_openstacksdk_hypervisor(self, **kwargs):
        """Create a real OpenStackSDK Hypervisor object.

        :param kwargs: hypervisor attributes
        :returns: openstack.compute.v2.hypervisor.Hypervisor object
        """
        name = kwargs.pop('name', 'hypervisor-hostname')
        hypervisor_info = {
            'id': kwargs.pop(
                'hypervisor_id', 'd010ef1f-dc19-4982-9383-087498bfde03'
            ),
            'name': name,
            'hypervisor_type': kwargs.pop('hypervisor_type', 'QEMU'),
            'state': kwargs.pop('state', 'up'),
            'status': kwargs.pop('status', 'enabled'),
            'vcpus': kwargs.pop('vcpus', 16),
            'vcpus_used': kwargs.pop('vcpus_used', 4),
            'memory_size': kwargs.pop('memory_size', 32768),
            'memory_used': kwargs.pop('memory_used', 8192),
            'local_disk_size': kwargs.pop('local_disk_size', 500),
            'local_disk_used': kwargs.pop('local_disk_used', 100),
            'service_details': kwargs.pop(
                'service_details', {'host': name, 'id': 1}
            ),
            'servers': kwargs.pop('servers', None),
        }
        hypervisor_info.update(kwargs)
        return hypervisor.Hypervisor(**hypervisor_info)

    def create_openstacksdk_flavor(self, **kwargs):
        """Create a real OpenStackSDK Flavor object.

        :param kwargs: flavor attributes
        :returns: openstack.compute.v2.flavor.Flavor object
        """
        flavor_info = {
            'id': kwargs.pop('id', 'flavor-id'),
            'name': kwargs.pop('name', 'm1.small'),
            'vcpus': kwargs.pop('vcpus', 2),
            'ram': kwargs.pop('ram', 2048),
            'disk': kwargs.pop('disk', 20),
            'ephemeral': kwargs.pop('ephemeral', 0),
            'swap': kwargs.pop('swap', 0),
            'is_public': kwargs.pop('is_public', True),
            'extra_specs': kwargs.pop('extra_specs', {}),
        }
        flavor_info.update(kwargs)
        return flavor.Flavor(**flavor_info)

    def create_openstacksdk_aggregate(self, **kwargs):
        """Create a real OpenStackSDK Aggregate object.

        :param kwargs: aggregate attributes
        :returns: openstack.compute.v2.aggregate.Aggregate object
        """
        aggregate_info = {
            'id': kwargs.pop('id', 'aggregate-id'),
            'name': kwargs.pop('name', 'test-aggregate'),
            'availability_zone': kwargs.pop('availability_zone', None),
            'hosts': kwargs.pop('hosts', []),
            'metadata': kwargs.pop('metadata', {}),
        }
        aggregate_info.update(kwargs)
        return aggregate.Aggregate(**aggregate_info)

    def create_openstacksdk_service(self, **kwargs):
        """Create a real OpenStackSDK Service object.

        :param kwargs: service attributes
        :returns: openstack.compute.v2.service.Service object
        """
        service_info = {
            'id': kwargs.pop('id', 'd010ef1f-dc19-4982-9383-087498bfde03'),
            'binary': kwargs.pop('binary', 'nova-compute'),
            'host': kwargs.pop('host', 'compute-1'),
            'availability_zone': kwargs.pop('availability_zone', 'nova'),
            'status': kwargs.pop('status', 'enabled'),
            'state': kwargs.pop('state', 'up'),
            'updated_at': kwargs.pop('updated_at', '2026-01-09T12:00:00Z'),
            'disabled_reason': kwargs.pop('disabled_reason', None),
        }
        service_info.update(kwargs)
        return service.Service(**service_info)

    def create_openstacksdk_migration(self, **kwargs):
        """Create a real OpenStackSDK ServerMigration object.

        :param kwargs: migration attributes
        :returns: openstack.compute.v2.server_migration.ServerMigration object
        """
        migration_info = {'id': kwargs.pop('id', 'migration-id')}
        migration_info.update(kwargs)
        return server_migration.ServerMigration(**migration_info)


class PlacementResourcesMixin:
    def create_openstacksdk_inventory(self, **kwargs):
        """Create an Inventory representation.

        :param kwargs: inventory attributes
        :returns: resource_provider_inventory.ResourceProviderInventory
        """
        inventory_info = {
            "resource_class": kwargs.pop('resource_class', 'VCPU'),
            "total": kwargs.pop('total', 0),
            "reserved": kwargs.pop('reserved', 0),
            "min_unit": kwargs.pop('min_unit', 1),
            "max_unit": kwargs.pop('max_unit', 0),
            "step_size": kwargs.pop('step_size', 1),
            "allocation_ratio": kwargs.pop('allocation_ratio', 1.0),
        }

        return resource_provider_inventory.ResourceProviderInventory(
            **inventory_info
        )


class CinderResourcesMixin:
    def create_openstacksdk_volume(self, **kwargs):
        """Create a real OpenStackSDK block_storage Volume.

        :param kwargs: volume attributes
        :returns: openstack.block_storage.v3.volume.Volume
        """
        volume_info = {
            'id': kwargs.pop('id', 'd010ef1f-dc19-4982-9383-087498bfde03'),
            'name': kwargs.pop('name', 'test-volume'),
            'size': kwargs.pop('size', 1),
            'status': kwargs.pop('status', 'available'),
            'volume_type': kwargs.pop('volume_type', 'fake_type'),
            'attachments': kwargs.pop('attachments', []),
            'is_multiattach': kwargs.pop('multiattach', False),
            'metadata': kwargs.pop('metadata', {}),
            'bootable': kwargs.pop('bootable', 'false'),
            'created_at': kwargs.pop('created_at', '2026-01-09T12:00:00'),
            'project_id': kwargs.pop('project_id', None),
            'os-vol-host-attr:host': kwargs.pop('host', None),
            'migration_status': kwargs.pop('migration_status', None),
            'os-vol-mig-status-attr:name_id': kwargs.pop('mig_name_id', None),
            'snapshot_id': kwargs.pop('snapshot_id', None),
        }
        volume_info.update(kwargs)
        return block_volume.Volume(**volume_info)

    def create_openstacksdk_pool(self, **kwargs):
        """Create a real OpenStackSDK block_storage Pools.

        :param kwargs: pool attributes
        :returns: openstack.block_storage.v3.stats.Pools
        """
        name = kwargs.pop('name', 'host@backend#pool')
        pool_name = kwargs.pop('pool_name', None)
        if pool_name is None and '#' in name:
            pool_name = name.split('#')[1]
        backend_name = kwargs.pop('volume_backend_name', None)
        if backend_name is None and '@' in name:
            backend_name = name.split('@')[1].split('#')[0]
        total_capacity_gb = kwargs.pop('total_capacity_gb', 100.0)
        free_capacity_gb = kwargs.pop('free_capacity_gb', 50.0)
        provisioned_capacity_gb = kwargs.pop('provisioned_capacity_gb', 50.0)
        allocated_capacity_gb = kwargs.pop('allocated_capacity_gb', 50.0)
        capabilities = kwargs.pop('capabilities', {})
        capabilities.setdefault('pool_name', pool_name)
        capabilities.setdefault('total_capacity_gb', total_capacity_gb)
        capabilities.setdefault('free_capacity_gb', free_capacity_gb)
        capabilities.setdefault(
            'provisioned_capacity_gb', provisioned_capacity_gb
        )
        capabilities.setdefault('allocated_capacity_gb', allocated_capacity_gb)
        capabilities.setdefault('volume_backend_name', backend_name)
        capabilities.setdefault(
            'total_volumes', kwargs.pop('total_volumes', 0)
        )
        capabilities.setdefault(
            'max_over_subscription_ratio',
            kwargs.pop('max_over_subscription_ratio', 1.0),
        )
        pool_info = {'name': name, 'capabilities': capabilities}
        return stats.Pools(**pool_info)

    def create_openstacksdk_storage_service(self, **kwargs):
        """Create a real OpenStackSDK block_storage Service.

        :param kwargs: service attributes
        :returns: openstack.block_storage.v3.service.Service
        """
        service_info = {
            'host': kwargs.pop('host', 'host@backend'),
            'zone': kwargs.pop('availability_zone', 'nova'),
            'state': kwargs.pop('state', 'up'),
            'status': kwargs.pop('status', 'enabled'),
        }
        service_info.update(kwargs)
        return block_service.Service(**service_info)

    def create_openstacksdk_volume_type(self, **kwargs):
        """Create a real OpenStackSDK block_storage Type.

        :param kwargs: volume type attributes
        :returns: openstack.block_storage.v3.type.Type
        """
        type_info = {
            'id': kwargs.pop('id', 'a1b2c3d4-e5f6-7890-abcd-ef1234567890'),
            'name': kwargs.pop('name', 'fake_type'),
            'extra_specs': kwargs.pop(
                'extra_specs', {'volume_backend_name': 'backend'}
            ),
        }
        type_info.update(kwargs)
        return block_type.Type(**type_info)

    def create_openstacksdk_volume_snapshot(self, **kwargs):
        """Create a real OpenStackSDK block_storage Snapshot.

        :param kwargs: snapshot attributes
        :returns: openstack.block_storage.v3.snapshot.Snapshot
        """
        snapshot_info = {
            'id': kwargs.pop(
                'id', 'snap-d010ef1f-dc19-4982-9383-087498bfde03'
            ),
            'status': kwargs.pop('status', 'available'),
            'volume_id': kwargs.pop(
                'volume_id', 'd010ef1f-dc19-4982-9383-087498bfde03'
            ),
        }
        snapshot_info.update(kwargs)
        return block_snapshot.Snapshot(**snapshot_info)
