"""
PM-Agent v1.2.0 E2E Tests

端到端测试，验证v1.2.0新功能的完整工作流程
"""
import os
import sys
import pytest
import tempfile
import shutil
from pathlib import Path
from unittest.mock import Mock, patch, MagicMock
from datetime import datetime

sys.path.insert(0, str(Path(__file__).parent.parent))


class TestGitSyncE2E:
    """Git同步服务 E2E测试"""

    @pytest.fixture
    def temp_workspace(self):
        """创建临时工作区"""
        temp = tempfile.mkdtemp()
        yield temp
        shutil.rmtree(temp, ignore_errors=True)

    @patch('backend.services.git_sync_service.Repo')
    def test_full_sync_workflow(self, mock_repo, temp_workspace):
        """测试完整同步工作流"""
        from backend.services.git_sync_service import GitSyncService
        
        mock_repo.clone_from.return_value = Mock()
        
        service = GitSyncService(base_path=temp_workspace)
        
        result = service.sync_project("test-repo", "https://github.com/test/repo.git")
        
        assert result.success is True
        assert result.project_name == "test-repo"

    def test_sync_without_remote(self, temp_workspace):
        """测试无远程仓库同步"""
        from backend.services.git_sync_service import GitSyncService
        
        project_dir = os.path.join(temp_workspace, "local-project")
        os.makedirs(os.path.join(project_dir, ".git"))
        
        service = GitSyncService(base_path=temp_workspace)
        
        result = service.sync_project("local-project")
        
        assert result is not None


class TestOcCollabE2E:
    """OcCollab客户端 E2E测试"""

    @patch('backend.services.oc_collab_client.shutil.which')
    @patch('backend.services.oc_collab_client.subprocess.run')
    def test_full_cli_workflow(self, mock_run, mock_which):
        """测试完整CLI工作流"""
        from backend.services.oc_collab_client import OcCollabClient
        
        mock_which.return_value = "/usr/bin/oc-collab"
        
        mock_result = Mock()
        mock_result.returncode = 0
        mock_result.stdout = '{"status": "active", "progress": 75}'
        mock_result.stderr = ''
        mock_run.return_value = mock_result
        
        client = OcCollabClient()
        
        status = client.get_project_status("test-project")
        
        assert status.status == "active"

    @patch('backend.services.oc_collab_client.shutil.which')
    @patch('backend.services.oc_collab_client.subprocess.run')
    def test_issue_sync_workflow(self, mock_run, mock_which):
        """测试问题同步工作流"""
        from backend.services.oc_collab_client import OcCollabClient
        
        mock_which.return_value = "/usr/bin/oc-collab"
        
        mock_result = Mock()
        mock_result.returncode = 0
        mock_result.stdout = '{"bugs": [], "requirements": []}'
        mock_result.stderr = ''
        mock_run.return_value = mock_result
        
        client = OcCollabClient()
        
        bugs = client.get_project_bugs("test-project")
        requirements = client.get_project_requirements("test-project")
        
        assert isinstance(bugs, list)
        assert isinstance(requirements, list)


class TestProgressTrackingE2E:
    """进度跟踪 E2E测试"""

    def test_progress_calculation_workflow(self):
        """测试进度计算工作流"""
        from backend.services.progress_service import (
            ProgressService, ProjectProgress,
            RequirementsProgress, BugsProgress, TodosProgress
        )
        
        service = ProgressService()
        
        progress = ProjectProgress(
            project_name="test-project",
            requirements=RequirementsProgress(total=10, completed=8, in_progress=1, pending=1),
            bugs=BugsProgress(total=5, resolved=4, open=1),
            todos=TodosProgress(total=20, completed=15, pending=5)
        )
        
        overall = service.calculate_overall_progress(progress)
        
        assert overall > 0
        assert overall <= 100

    def test_weight_customization(self):
        """测试权重自定义"""
        from backend.services.progress_service import ProgressService
        
        service = ProgressService()
        
        service.set_weights(requirements=0.5, bugs=0.3, todos=0.2)
        
        assert service._requirements_weight == 0.5
        assert service._bugs_weight == 0.3
        assert service._todos_weight == 0.2


class TestStatusFeedbackE2E:
    """状态反馈 E2E测试"""

    def test_change_notification_workflow(self):
        """测试变更通知工作流"""
        from backend.services.status_feedback_service import (
            StatusFeedbackService, ChangeEvent, ChangeType
        )
        
        service = StatusFeedbackService()
        
        events_received = []
        
        def callback(event):
            events_received.append(event)
        
        service.register_callback(callback)
        
        event = ChangeEvent(
            project_name="test-project",
            change_type=ChangeType.REQUIREMENT,
            change_id="REQ-001",
            title="New requirement",
            old_status="draft",
            new_status="proposed"
        )
        
        service._notify_callbacks(event)
        
        assert len(events_received) == 1
        assert events_received[0].change_id == "REQ-001"

    def test_multiple_callbacks(self):
        """测试多个回调"""
        from backend.services.status_feedback_service import (
            StatusFeedbackService, ChangeEvent, ChangeType
        )
        
        service = StatusFeedbackService()
        
        call_count = [0]
        
        def callback1(event):
            call_count[0] += 1
        
        def callback2(event):
            call_count[0] += 1
        
        service.register_callback(callback1)
        service.register_callback(callback2)
        
        event = ChangeEvent(
            project_name="test-project",
            change_type=ChangeType.BUG,
            change_id="BUG-001",
            title="Bug fix",
            old_status="open",
            new_status="closed"
        )
        
        service._notify_callbacks(event)
        
        assert call_count[0] == 2


class TestIssueSyncE2E:
    """问题同步 E2E测试"""

    @patch('backend.services.issue_sync_service.IssueSyncService.sync_bugs')
    @patch('backend.services.issue_sync_service.IssueSyncService.sync_requirements')
    def test_full_issue_sync(self, mock_req, mock_bugs):
        """测试完整问题同步"""
        from backend.services.issue_sync_service import IssueSyncService
        
        mock_bugs.return_value = []
        mock_req.return_value = []
        
        service = IssueSyncService()
        
        result = service.sync_all_issues("test-project")
        
        assert 'bugs_synced' in result
        assert 'requirements_synced' in result


class TestDocumentFetchE2E:
    """文档拉取 E2E测试"""

    @pytest.fixture
    def temp_docs(self):
        temp = tempfile.mkdtemp()
        
        os.makedirs(os.path.join(temp, "docs"))
        os.makedirs(os.path.join(temp, "src"))
        
        with open(os.path.join(temp, "README.md"), "w") as f:
            f.write("# Test Project\n\nThis is a test.")
        
        with open(os.path.join(temp, "docs", "guide.md"), "w") as f:
            f.write("# User Guide\n\nUsage instructions.")
        
        with open(os.path.join(temp, "src", "app.py"), "w") as f:
            f.write("def main(): pass")
        
        yield temp
        shutil.rmtree(temp, ignore_errors=True)

    def test_document_discovery(self, temp_docs):
        """测试文档发现"""
        from backend.services.document_fetcher import DocumentFetcher
        
        fetcher = DocumentFetcher()
        
        docs = fetcher.fetch_docs(temp_docs)
        
        assert len(docs) > 0
        assert any(d.name == "README.md" for d in docs)

    def test_category_classification(self, temp_docs):
        """测试分类"""
        from backend.services.document_fetcher import DocumentFetcher
        
        fetcher = DocumentFetcher()
        
        docs = fetcher.fetch_docs(temp_docs)
        
        categories = set(d.category for d in docs)
        
        assert "文档" in categories or "源代码" in categories


class TestConfidentialCheckE2E:
    """保密检查 E2E测试"""

    @pytest.fixture
    def temp_project(self):
        temp = tempfile.mkdtemp()
        
        with open(os.path.join(temp, "public.txt"), "w") as f:
            f.write("This is public information.")
        
        with open(os.path.join(temp, "secret.txt"), "w") as f:
            f.write("This contains password: secret123")
        
        yield temp
        shutil.rmtree(temp, ignore_errors=True)

    def test_sensitive_detection(self, temp_project):
        """测试敏感信息检测"""
        from backend.services.confidential_checker import SensitiveContentChecker
        
        checker = SensitiveContentChecker()
        
        result = checker.check_files(temp_project)
        
        assert result is not None
        assert result.files_count >= 0

    def test_keyword_management(self):
        """测试关键词管理"""
        from backend.services.confidential_checker import SensitiveContentChecker
        
        checker = SensitiveContentChecker()
        
        original_count = len(checker.keywords)
        
        checker.add_keyword("custom_test_keyword")
        
        assert len(checker.keywords) > original_count
        
        checker.remove_keyword("custom_test_keyword")
        
        assert len(checker.keywords) == original_count


class TestSyncPermissionE2E:
    """同步权限 E2E测试"""

    def test_permission_check_workflow(self):
        """测试权限检查工作流"""
        from backend.services.sync_permission_service import SyncPermissionService
        
        service = SyncPermissionService()
        
        result = service.check_sync_safety("test-project")
        
        assert 'is_safe' in result

    def test_confidential_project_check(self):
        """测试保密项目检查"""
        from backend.services.sync_permission_service import SyncPermissionService
        
        service = SyncPermissionService()
        
        result = service.check_sync_safety("confidential-project")
        
        assert 'is_safe' in result

    def test_sync_recommendation(self):
        """测试同步建议"""
        from backend.services.sync_permission_service import SyncPermissionService
        
        service = SyncPermissionService()
        
        result = service.get_sync_recommendation()
        
        assert result is not None


class TestIntegrationWorkflow:
    """集成工作流测试"""

    def test_git_to_progress_workflow(self):
        """测试Git同步到进度跟踪工作流"""
        from backend.services.git_sync_service import GitSyncService
        from backend.services.progress_service import ProgressService
        
        git_service = GitSyncService()
        progress_service = ProgressService()
        
        progress = progress_service.get_project_progress("test-project")
        
        assert progress is not None

    def test_issue_to_feedback_workflow(self):
        """测试问题同步到反馈工作流"""
        from backend.services.issue_sync_service import IssueSyncService
        from backend.services.status_feedback_service import StatusFeedbackService
        
        issue_service = IssueSyncService()
        feedback_service = StatusFeedbackService()
        
        bugs = issue_service.sync_bugs("test-project")
        
        assert isinstance(bugs, list)

    def test_confidential_to_permission_workflow(self):
        """测试保密检查到权限工作流"""
        from backend.services.confidential_checker import SensitiveContentChecker
        from backend.services.sync_permission_service import SyncPermissionService
        
        checker = SensitiveContentChecker()
        perm_service = SyncPermissionService()
        
        perm_result = perm_service.check_sync_safety("test-project")
        
        assert 'is_safe' in perm_result


if __name__ == "__main__":
    pytest.main([__file__, "-v", "--tb=short"])
