from django.test import TestCase
from django.contrib.auth import get_user_model
from rest_framework.test import APITestCase, APIClient
from rest_framework import status
from rest_framework_simplejwt.tokens import RefreshToken
from .models import Permission, Role, UserCompanyRole
from apps.companies.models import Company

User = get_user_model()


class PermissionsSecurityTestCase(APITestCase):
    """Test permissions and roles security features"""
    
    def setUp(self):
        """Set up test data"""
        # Create super admin
        self.super_admin = User.objects.create_user(
            email='superadmin@test.com',
            username='superadmin',
            password='password123',
            user_type='super_admin'
        )
        self.super_admin.is_superuser = True
        self.super_admin.is_active = True  # Activate the user
        self.super_admin.save()
        
        # Create companies
        self.company1 = Company.objects.create(
            name='Company 1',
            phone='+1234567890',
            office_time='9 AM - 6 PM',
            timezone='UTC'
        )
        self.company2 = Company.objects.create(
            name='Company 2',
            phone='+9876543210',
            office_time='8 AM - 5 PM',
            timezone='UTC'
        )
        
        # Create regular users
        self.user1 = User.objects.create_user(
            email='user1@test.com',
            username='user1',
            password='password123'
        )
        self.user1.is_active = True  # Activate the user
        self.user1.save()
        
        self.user2 = User.objects.create_user(
            email='user2@test.com',
            username='user2',
            password='password123'
        )
        self.user2.is_active = True  # Activate the user
        self.user2.save()
        
        # Add users to companies
        self.user1.companies.add(self.company1)
        self.user1.active_company = self.company1
        self.user1.save()
        
        self.user2.companies.add(self.company2)
        self.user2.active_company = self.company2
        self.user2.save()
        
        # Create permissions
        self.view_roles_perm = Permission.objects.create(
            name='View Roles',
            codename='view_roles'
        )
        self.create_roles_perm = Permission.objects.create(
            name='Create Roles',
            codename='create_roles'
        )
        self.edit_roles_perm = Permission.objects.create(
            name='Edit Roles',
            codename='edit_roles'
        )
        self.delete_roles_perm = Permission.objects.create(
            name='Delete Roles',
            codename='delete_roles'
        )
        self.view_permissions_perm = Permission.objects.create(
            name='View Permissions',
            codename='view_permissions'
        )
        
        # Create roles in different companies
        self.role1 = Role.objects.create(
            name='Role 1',
            description='Role in Company 1',
            company=self.company1
        )
        self.role1.permissions.add(
            self.view_roles_perm,
            self.create_roles_perm,
            self.edit_roles_perm,
            self.delete_roles_perm
        )
        
        self.role2 = Role.objects.create(
            name='Role 2',
            description='Role in Company 2',
            company=self.company2
        )
        self.role2.permissions.add(
            self.view_roles_perm,
            self.create_roles_perm
        )
        
        # Assign roles to users
        UserCompanyRole.objects.create(
            user=self.user1,
            company=self.company1,
            role=self.role1
        )
        
        UserCompanyRole.objects.create(
            user=self.user2,
            company=self.company2,
            role=self.role2
        )
        
        # Setup API clients
        self.super_client = APIClient()
        self.user1_client = APIClient()
        self.user2_client = APIClient()
        
        # Get tokens
        super_refresh = RefreshToken.for_user(self.super_admin)
        user1_refresh = RefreshToken.for_user(self.user1)
        user2_refresh = RefreshToken.for_user(self.user2)
        
        self.super_client.credentials(HTTP_AUTHORIZATION=f'Bearer {super_refresh.access_token}')
        self.user1_client.credentials(HTTP_AUTHORIZATION=f'Bearer {user1_refresh.access_token}')
        self.user2_client.credentials(HTTP_AUTHORIZATION=f'Bearer {user2_refresh.access_token}')
    
    def test_super_admin_can_create_role_for_any_company(self):
        """Super admin should be able to create roles for any company"""
        data = {
            'name': 'Super Admin Role',
            'description': 'Role created by super admin',
            'company': self.company2.id,
            'permission_ids': [self.view_roles_perm.id]
        }
        
        response = self.super_client.post('/api/permissions/roles/', data)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        
        # Role should be created in company2
        role = Role.objects.get(name='Super Admin Role')
        self.assertEqual(role.company, self.company2)
    
    def test_regular_user_cannot_create_role_for_other_company(self):
        """Regular user cannot create role for company they don't belong to"""
        data = {
            'name': 'Unauthorized Role',
            'description': 'Role for other company',
            'company': self.company2.id,
            'permission_ids': [self.view_roles_perm.id]
        }
        
        response = self.user1_client.post('/api/permissions/roles/', data)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertIn('You can only create roles for companies you belong to', str(response.data))
    
    def test_regular_user_can_create_role_for_own_company(self):
        """Regular user can create role for company they belong to"""
        data = {
            'name': 'Authorized Role',
            'description': 'Role for own company',
            'company': self.company1.id,
            'permission_ids': [self.view_roles_perm.id]
        }
        
        response = self.user1_client.post('/api/permissions/roles/', data)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        
        # Role should be created in company1
        role = Role.objects.get(name='Authorized Role')
        self.assertEqual(role.company, self.company1)
    
    def test_role_creation_falls_back_to_active_company(self):
        """Role creation without company specified uses active company"""
        data = {
            'name': 'Default Company Role',
            'description': 'Role for active company',
            'permission_ids': [self.view_roles_perm.id]
        }
        
        response = self.user1_client.post('/api/permissions/roles/', data)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        
        # Role should be created in user's active company
        role = Role.objects.get(name='Default Company Role')
        self.assertEqual(role.company, self.company1)
    
    def test_super_admin_can_edit_any_role(self):
        """Super admin should be able to edit any role"""
        data = {'name': 'Updated Role Name'}
        
        response = self.super_client.patch(f'/api/permissions/roles/{self.role1.id}/', data)
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        
        self.role1.refresh_from_db()
        self.assertEqual(self.role1.name, 'Updated Role Name')
    
    def test_regular_user_cannot_edit_role_without_permission(self):
        """Regular user without edit_roles permission cannot edit roles"""
        # Remove edit_roles permission from role
        self.role1.permissions.remove(self.edit_roles_perm)
        
        data = {'name': 'Unauthorized Edit'}
        
        response = self.user1_client.patch(f'/api/permissions/roles/{self.role1.id}/', data)
        self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
        
        # Role should not be changed
        self.role1.refresh_from_db()
        self.assertEqual(self.role1.name, 'Role 1')
    
    def test_regular_user_can_edit_role_with_permission(self):
        """Regular user with edit_roles permission can edit roles"""
        data = {'name': 'Authorized Edit'}
        
        response = self.user1_client.patch(f'/api/permissions/roles/{self.role1.id}/', data)
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        
        self.role1.refresh_from_db()
        self.assertEqual(self.role1.name, 'Authorized Edit')
    
    def test_role_queryset_filtered_by_active_company(self):
        """Users should only see roles from their active company"""
        # User1 should only see roles from company1
        response = self.user1_client.get('/api/permissions/roles/')
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        
        role_names = [role['name'] for role in response.data]
        self.assertIn('Role 1', role_names)
        self.assertNotIn('Role 2', role_names)
        
        # User2 should only see roles from company2
        response = self.user2_client.get('/api/permissions/roles/')
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        
        role_names = [role['name'] for role in response.data]
        self.assertIn('Role 2', role_names)
        self.assertNotIn('Role 1', role_names)
    
    def test_super_admin_sees_all_roles(self):
        """Super admin should see all roles from all companies"""
        response = self.super_client.get('/api/permissions/roles/')
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        
        role_names = [role['name'] for role in response.data]
        self.assertIn('Role 1', role_names)
        self.assertIn('Role 2', role_names)
    
    def test_role_assignment_requires_same_company(self):
        """Role can only be assigned to users in the same company"""
        # Try to assign role1 (company1) to user2 (company2)
        data = {'user_id': self.user2.id}
        
        response = self.user1_client.post(f'/api/permissions/roles/{self.role1.id}/assign_to_user/', data)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertIn('belong to different companies', str(response.data))
    
    def test_role_assignment_successful_in_same_company(self):
        """Role assignment successful when user and role are in same company"""
        # Create new user in company1
        new_user = User.objects.create_user(
            email='newuser@test.com',
            username='newuser',
            password='password123'
        )
        new_user.companies.add(self.company1)
        new_user.save()
        
        data = {'user_id': new_user.id}
        
        response = self.user1_client.post(f'/api/permissions/roles/{self.role1.id}/assign_to_user/', data)
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        
        # Check if UserCompanyRole was created
        user_role = UserCompanyRole.objects.get(user=new_user, company=self.company1)
        self.assertEqual(user_role.role, self.role1)
    
    def test_permissions_list_filtered_by_company(self):
        """Permissions list should only show permissions relevant to user's active company"""
        # User1 should see permissions used in company1
        response = self.user1_client.get('/api/permissions/permissions/')
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        
        # Should see permissions that are used in company1 roles
        permission_codenames = [perm['codename'] for perm in response.data]
        self.assertIn('view_roles', permission_codenames)
        self.assertIn('create_roles', permission_codenames)
        self.assertIn('edit_roles', permission_codenames)
        self.assertIn('delete_roles', permission_codenames)
    
    def test_super_admin_sees_all_permissions(self):
        """Super admin should see all permissions"""
        response = self.super_client.get('/api/permissions/permissions/')
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        
        # Should see all permissions
        permission_codenames = [perm['codename'] for perm in response.data]
        self.assertIn('view_roles', permission_codenames)
        self.assertIn('create_roles', permission_codenames)
        self.assertIn('edit_roles', permission_codenames)
        self.assertIn('delete_roles', permission_codenames)
        self.assertIn('view_permissions', permission_codenames)
    
    def test_unique_role_name_validation_within_company(self):
        """Role names should be unique within a company"""
        # Try to create role with same name in same company
        data = {
            'name': 'Role 1',  # Same name as existing role
            'description': 'Duplicate role',
            'company': self.company1.id,
            'permission_ids': [self.view_roles_perm.id]
        }
        
        response = self.user1_client.post('/api/permissions/roles/', data)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertIn('already exists in company', str(response.data))
    
    def test_role_name_can_be_duplicated_across_companies(self):
        """Role names can be duplicated across different companies"""
        # Create role with same name in different company
        data = {
            'name': 'Role 1',  # Same name as role in company1
            'description': 'Role in different company',
            'company': self.company2.id,
            'permission_ids': [self.view_roles_perm.id]
        }
        
        response = self.user2_client.post('/api/permissions/roles/', data)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        
        # Both roles should exist with same name in different companies
        roles = Role.objects.filter(name='Role 1')
        self.assertEqual(roles.count(), 2)
        companies = [role.company for role in roles]
        self.assertIn(self.company1, companies)
        self.assertIn(self.company2, companies)
