from unittest import mock
import json
import uuid

from vmms.tests import base


class TestVMMSServiceAPI(base.VMMSTestCase):
    """Test VMMS service API endpoints."""

    def setUp(self):
        super(TestVMMSServiceAPI, self).setUp()
        
        # Mock database session
        self.session_patcher = mock.patch('vmms.db.sqlalchemy.database.get_session')
        self.mock_session = self.session_patcher.start()
        self.addCleanup(self.session_patcher.stop)
        
        # Mock the config module to avoid initialization
        self.config_module_patcher = mock.patch('vmms.config.init_config')
        self.mock_init_config = self.config_module_patcher.start()
        self.mock_init_config.return_value = mock.Mock()  # Return mock config
        self.addCleanup(self.config_module_patcher.stop)
        
        # Mock get_vm_details_from_source_cloud
        self.vm_details_patcher = mock.patch('vmms.api.get_vm_details_from_source_cloud')
        self.mock_get_vm_details = self.vm_details_patcher.start()
        self.addCleanup(self.vm_details_patcher.stop)
        
        # Mock policy enforcement to always allow (for functional tests)
        self.policy_patcher = mock.patch('vmms.policy.enforcer.enforce_policy')
        self.mock_enforce_policy = self.policy_patcher.start()
        self.mock_enforce_policy.return_value = True  # Always allow policy
        self.addCleanup(self.policy_patcher.stop)

    def test_healthcheck_endpoint(self):
        """Test health check endpoint."""
        response = self.client.get('/healthcheck')
        self.assertEqual(response.status_code, 200)
        data = json.loads(response.data)
        self.assertEqual(data['status'], 'ok')
        self.assertEqual(data['service'], 'vmms')

    def test_add_vm_missing_vm_identifier(self):
        """Test adding VM without vm_identifier."""
        headers = self._create_test_headers(roles=['vmms_operator'])
        response = self.client.post('/v2/vms', headers=headers, json={})
        self.assertEqual(response.status_code, 400)
        data = json.loads(response.data)
        self.assertIn('error', data)

    def test_invalid_migration_id_format(self):
        """Test API with invalid migration ID format."""
        # Mock the is_valid_uuid function to return False for invalid IDs
        with mock.patch('vmms.api.is_valid_uuid', return_value=False):
            headers = self._create_test_headers(roles=['vmms_operator'])
            response = self.client.get('/v2/vms/invalid-id', headers=headers)
            self.assertEqual(response.status_code, 400)


class TestVMMSPolicyDeny(base.VMMSTestCase):
    """Test that policy denials work correctly."""

    def setUp(self):
        super(TestVMMSPolicyDeny, self).setUp()
        
        # Mock database session
        self.session_patcher = mock.patch('vmms.db.sqlalchemy.database.get_session')
        self.mock_session = self.session_patcher.start()
        self.addCleanup(self.session_patcher.stop)
        
        # Mock the config module to avoid initialization
        self.config_module_patcher = mock.patch('vmms.config.init_config')
        self.mock_init_config = self.config_module_patcher.start()
        self.mock_init_config.return_value = mock.Mock()  # Return mock config
        self.addCleanup(self.config_module_patcher.stop)
        
        # Mock get_vm_details_from_source_cloud
        self.vm_details_patcher = mock.patch('vmms.api.get_vm_details_from_source_cloud')
        self.mock_get_vm_details = self.vm_details_patcher.start()
        self.addCleanup(self.vm_details_patcher.stop)
        
        # Mock the policy enforcer to raise exceptions for denied access
        self.policy_patcher = mock.patch('vmms.policy.enforcer.enforce_policy')
        self.mock_enforce_policy = self.policy_patcher.start()
        self.addCleanup(self.policy_patcher.stop)

    def test_viewer_cannot_add_vm(self):
        """Test that vmms_viewer users cannot add VMs."""
        # Make policy enforcement raise an exception for add operations by viewers
        def mock_enforce_policy_side_effect(*args, **kwargs):
            # Simulate a policy denial by raising an exception
            from oslo_policy import policy as oslo_policy
            raise oslo_policy.PolicyNotAuthorized('vmms:add', {}, {})
        
        self.mock_enforce_policy.side_effect = mock_enforce_policy_side_effect
        
        headers = self._create_test_headers(roles=['vmms_viewer'])
        response = self.client.post('/v2/vms', headers=headers, json={
            'vm_identifier': 'test-vm'
        })
        # Should be forbidden (the decorator catches the exception and returns 403)
        self.assertEqual(response.status_code, 403)
