"""
Test IT Audit Collaboration Matching
====================================

Tests for the collaboration matching functionality in IT Audit Service.

Test cases:
1. Backup replication matching (Proxmox PBS)
2. Shared licensing matching (M365)
3. Teams federation matching (Azure AD)
4. Shared monitoring matching (Zabbix)
5. Collective purchasing matching (similar size)
6. Knowledge sharing matching (similar tech stack)

Author: Norda Biznes Development Team
Created: 2026-01-09
"""

import os
import sys
import unittest
from unittest.mock import MagicMock, patch
from dataclasses import dataclass

# Add parent directory (worktree root) to path for imports
WORKTREE_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0, WORKTREE_ROOT)

# Mock database module before importing it_audit_service
# This prevents database connection errors during import
sys.modules['database'] = MagicMock()

# Now we can safely import it_audit_service
from it_audit_service import ITAuditService, CollaborationMatch


class MockCompany:
    """Mock Company object for testing"""
    def __init__(self, id: int, name: str, slug: str):
        self.id = id
        self.name = name
        self.slug = slug


class MockITAudit:
    """Mock ITAudit object for testing"""
    def __init__(self, **kwargs):
        self.company_id = kwargs.get('company_id', 1)

        # Collaboration flags
        self.open_to_shared_licensing = kwargs.get('open_to_shared_licensing', False)
        self.open_to_backup_replication = kwargs.get('open_to_backup_replication', False)
        self.open_to_teams_federation = kwargs.get('open_to_teams_federation', False)
        self.open_to_shared_monitoring = kwargs.get('open_to_shared_monitoring', False)
        self.open_to_collective_purchasing = kwargs.get('open_to_collective_purchasing', False)
        self.open_to_knowledge_sharing = kwargs.get('open_to_knowledge_sharing', False)

        # Technology flags
        self.has_azure_ad = kwargs.get('has_azure_ad', False)
        self.azure_tenant_name = kwargs.get('azure_tenant_name', None)
        self.has_m365 = kwargs.get('has_m365', False)
        self.m365_plans = kwargs.get('m365_plans', [])
        self.has_proxmox_pbs = kwargs.get('has_proxmox_pbs', False)
        self.monitoring_solution = kwargs.get('monitoring_solution', None)

        # Size info
        self.employee_count = kwargs.get('employee_count', None)

        # Tech stack
        self.virtualization_platform = kwargs.get('virtualization_platform', None)
        self.backup_solution = kwargs.get('backup_solution', None)
        self.network_firewall_brand = kwargs.get('network_firewall_brand', None)
        self.erp_system = kwargs.get('erp_system', None)


class TestCollaborationMatching(unittest.TestCase):
    """Test collaboration matching logic without database"""

    def setUp(self):
        """Set up test fixtures"""
        # Create service without database (we'll test internal methods)
        self.service = ITAuditService.__new__(ITAuditService)

    def test_backup_replication_match_both_have_pbs_and_open(self):
        """Test backup replication match when both companies have PBS and are open"""
        company_a = MockCompany(1, "Firma A", "firma-a")
        company_b = MockCompany(2, "Firma B", "firma-b")

        audit_a = MockITAudit(
            company_id=1,
            has_proxmox_pbs=True,
            open_to_backup_replication=True
        )
        audit_b = MockITAudit(
            company_id=2,
            has_proxmox_pbs=True,
            open_to_backup_replication=True
        )

        matches = self.service._check_all_match_types(
            company_a, audit_a, company_b, audit_b
        )

        # Should have exactly 1 match for backup_replication
        backup_matches = [m for m in matches if m.match_type == 'backup_replication']
        self.assertEqual(len(backup_matches), 1)

        match = backup_matches[0]
        self.assertEqual(match.company_a_id, 1)
        self.assertEqual(match.company_b_id, 2)
        self.assertEqual(match.match_type, 'backup_replication')
        self.assertEqual(match.match_score, 90)
        self.assertIn('Proxmox PBS', match.match_reason)

    def test_backup_replication_no_match_only_one_has_pbs(self):
        """Test no backup match when only one company has PBS"""
        company_a = MockCompany(1, "Firma A", "firma-a")
        company_b = MockCompany(2, "Firma B", "firma-b")

        audit_a = MockITAudit(
            company_id=1,
            has_proxmox_pbs=True,
            open_to_backup_replication=True
        )
        audit_b = MockITAudit(
            company_id=2,
            has_proxmox_pbs=False,  # Company B doesn't have PBS
            open_to_backup_replication=True
        )

        matches = self.service._check_all_match_types(
            company_a, audit_a, company_b, audit_b
        )

        backup_matches = [m for m in matches if m.match_type == 'backup_replication']
        self.assertEqual(len(backup_matches), 0)

    def test_backup_replication_no_match_not_open(self):
        """Test no backup match when one company is not open"""
        company_a = MockCompany(1, "Firma A", "firma-a")
        company_b = MockCompany(2, "Firma B", "firma-b")

        audit_a = MockITAudit(
            company_id=1,
            has_proxmox_pbs=True,
            open_to_backup_replication=True
        )
        audit_b = MockITAudit(
            company_id=2,
            has_proxmox_pbs=True,
            open_to_backup_replication=False  # Company B not open
        )

        matches = self.service._check_all_match_types(
            company_a, audit_a, company_b, audit_b
        )

        backup_matches = [m for m in matches if m.match_type == 'backup_replication']
        self.assertEqual(len(backup_matches), 0)

    def test_shared_licensing_match_both_have_m365_and_open(self):
        """Test shared licensing match when both have M365 and are open"""
        company_a = MockCompany(1, "Firma A", "firma-a")
        company_b = MockCompany(2, "Firma B", "firma-b")

        audit_a = MockITAudit(
            company_id=1,
            has_m365=True,
            m365_plans=['Business Basic', 'E3'],
            open_to_shared_licensing=True
        )
        audit_b = MockITAudit(
            company_id=2,
            has_m365=True,
            m365_plans=['E3', 'E5'],
            open_to_shared_licensing=True
        )

        matches = self.service._check_all_match_types(
            company_a, audit_a, company_b, audit_b
        )

        licensing_matches = [m for m in matches if m.match_type == 'shared_licensing']
        self.assertEqual(len(licensing_matches), 1)

        match = licensing_matches[0]
        self.assertEqual(match.match_score, 80)
        self.assertIn('Microsoft 365', match.match_reason)

    def test_teams_federation_match_both_have_azure_ad_and_open(self):
        """Test Teams federation match when both have Azure AD and are open"""
        company_a = MockCompany(1, "Firma A", "firma-a")
        company_b = MockCompany(2, "Firma B", "firma-b")

        audit_a = MockITAudit(
            company_id=1,
            has_azure_ad=True,
            azure_tenant_name='firmaa.onmicrosoft.com',
            open_to_teams_federation=True
        )
        audit_b = MockITAudit(
            company_id=2,
            has_azure_ad=True,
            azure_tenant_name='firmab.onmicrosoft.com',
            open_to_teams_federation=True
        )

        matches = self.service._check_all_match_types(
            company_a, audit_a, company_b, audit_b
        )

        teams_matches = [m for m in matches if m.match_type == 'teams_federation']
        self.assertEqual(len(teams_matches), 1)

        match = teams_matches[0]
        self.assertEqual(match.match_score, 85)
        self.assertIn('Azure AD', match.match_reason)

    def test_shared_monitoring_match_both_use_zabbix(self):
        """Test shared monitoring match when both use Zabbix"""
        company_a = MockCompany(1, "Firma A", "firma-a")
        company_b = MockCompany(2, "Firma B", "firma-b")

        audit_a = MockITAudit(
            company_id=1,
            monitoring_solution='Zabbix',
            open_to_shared_monitoring=True
        )
        audit_b = MockITAudit(
            company_id=2,
            monitoring_solution='Zabbix 6.0',
            open_to_shared_monitoring=True
        )

        matches = self.service._check_all_match_types(
            company_a, audit_a, company_b, audit_b
        )

        monitoring_matches = [m for m in matches if m.match_type == 'shared_monitoring']
        self.assertEqual(len(monitoring_matches), 1)

        match = monitoring_matches[0]
        self.assertEqual(match.match_score, 75)
        self.assertIn('Zabbix', match.match_reason)

    def test_collective_purchasing_match_similar_size(self):
        """Test collective purchasing match for similar company sizes"""
        company_a = MockCompany(1, "Firma A", "firma-a")
        company_b = MockCompany(2, "Firma B", "firma-b")

        audit_a = MockITAudit(
            company_id=1,
            employee_count='11-50',
            open_to_collective_purchasing=True
        )
        audit_b = MockITAudit(
            company_id=2,
            employee_count='51-100',  # Similar size (within 3x ratio)
            open_to_collective_purchasing=True
        )

        matches = self.service._check_all_match_types(
            company_a, audit_a, company_b, audit_b
        )

        purchasing_matches = [m for m in matches if m.match_type == 'collective_purchasing']
        self.assertEqual(len(purchasing_matches), 1)

        match = purchasing_matches[0]
        self.assertEqual(match.match_score, 70)

    def test_knowledge_sharing_match_similar_tech_stack(self):
        """Test knowledge sharing match for similar tech stack"""
        company_a = MockCompany(1, "Firma A", "firma-a")
        company_b = MockCompany(2, "Firma B", "firma-b")

        audit_a = MockITAudit(
            company_id=1,
            virtualization_platform='Proxmox',
            backup_solution='Veeam',
            has_azure_ad=True,
            has_m365=True,
            open_to_knowledge_sharing=True
        )
        audit_b = MockITAudit(
            company_id=2,
            virtualization_platform='Proxmox',
            backup_solution='Veeam',
            has_azure_ad=True,
            has_m365=True,
            open_to_knowledge_sharing=True
        )

        matches = self.service._check_all_match_types(
            company_a, audit_a, company_b, audit_b
        )

        knowledge_matches = [m for m in matches if m.match_type == 'knowledge_sharing']
        self.assertEqual(len(knowledge_matches), 1)

        match = knowledge_matches[0]
        self.assertEqual(match.match_score, 65)
        # Should have at least 2 common technologies
        self.assertIn('common_tech', match.shared_attributes)
        self.assertGreaterEqual(len(match.shared_attributes['common_tech']), 2)

    def test_multiple_matches_for_same_companies(self):
        """Test that multiple match types can be found for the same company pair"""
        company_a = MockCompany(1, "Firma A", "firma-a")
        company_b = MockCompany(2, "Firma B", "firma-b")

        # Both companies have multiple collaboration opportunities
        audit_a = MockITAudit(
            company_id=1,
            has_proxmox_pbs=True,
            has_azure_ad=True,
            has_m365=True,
            open_to_backup_replication=True,
            open_to_teams_federation=True,
            open_to_shared_licensing=True
        )
        audit_b = MockITAudit(
            company_id=2,
            has_proxmox_pbs=True,
            has_azure_ad=True,
            has_m365=True,
            open_to_backup_replication=True,
            open_to_teams_federation=True,
            open_to_shared_licensing=True
        )

        matches = self.service._check_all_match_types(
            company_a, audit_a, company_b, audit_b
        )

        # Should have matches for backup_replication, teams_federation, and shared_licensing
        match_types = {m.match_type for m in matches}
        self.assertIn('backup_replication', match_types)
        self.assertIn('teams_federation', match_types)
        self.assertIn('shared_licensing', match_types)
        self.assertEqual(len(matches), 3)

    def test_parse_count_range(self):
        """Test employee count range parsing"""
        self.assertEqual(self.service._parse_count_range('1-10'), 5)
        self.assertEqual(self.service._parse_count_range('11-50'), 30)
        self.assertEqual(self.service._parse_count_range('51-100'), 75)
        self.assertEqual(self.service._parse_count_range('101-250'), 175)
        self.assertEqual(self.service._parse_count_range('251-500'), 375)
        self.assertEqual(self.service._parse_count_range('500+'), 750)
        self.assertIsNone(self.service._parse_count_range(None))
        self.assertIsNone(self.service._parse_count_range('unknown'))

    def test_sizes_similar(self):
        """Test company size similarity check"""
        # Within 3x ratio should be similar
        self.assertTrue(self.service._sizes_similar(30, 75))  # 2.5x
        self.assertTrue(self.service._sizes_similar(30, 30))  # 1x
        self.assertTrue(self.service._sizes_similar(30, 50))  # 1.67x

        # More than 3x ratio should not be similar
        self.assertFalse(self.service._sizes_similar(5, 175))  # 35x
        self.assertFalse(self.service._sizes_similar(5, 750))  # 150x

        # Zero handling
        self.assertFalse(self.service._sizes_similar(0, 50))
        self.assertFalse(self.service._sizes_similar(50, 0))


class TestCollaborationMatchDataclass(unittest.TestCase):
    """Test CollaborationMatch dataclass"""

    def test_collaboration_match_creation(self):
        """Test creating a CollaborationMatch"""
        match = CollaborationMatch(
            company_a_id=1,
            company_b_id=2,
            company_a_name="Firma A",
            company_b_name="Firma B",
            match_type="backup_replication",
            match_reason="Obie firmy używają Proxmox PBS",
            match_score=90,
            shared_attributes={"pbs": True}
        )

        self.assertEqual(match.company_a_id, 1)
        self.assertEqual(match.company_b_id, 2)
        self.assertEqual(match.match_type, "backup_replication")
        self.assertEqual(match.match_score, 90)
        self.assertEqual(match.shared_attributes["pbs"], True)


if __name__ == '__main__':
    unittest.main(verbosity=2)
