"""
PM-Agent v1.2.0 Additional Tests - Coverage Boost

补充测试用例，用于提高v1.2.0新服务的代码覆盖率至80%以上
"""
import os
import sys
import pytest
import tempfile
from pathlib import Path
from unittest.mock import Mock, patch
from datetime import datetime

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


class TestGitSyncServiceExtra:
    """GitSyncService 额外测试"""

    def test_sync_result_str(self):
        """测试SyncResult字符串表示"""
        from backend.services.git_sync_service import SyncResult
        result = SyncResult(success=True, project_name="test", started_at=datetime.now())
        assert result.project_name == "test"

    @patch('backend.services.git_sync_service.Repo')
    def test_repo_clone_error(self, mock_repo):
        """测试克隆错误"""
        from backend.services.git_sync_service import GitSyncService
        import tempfile
        temp = tempfile.mkdtemp()
        
        mock_repo.clone_from.side_effect = Exception("Clone failed")
        
        service = GitSyncService(base_path=temp)
        result = service._clone_repo("https://github.com/test/repo.git", temp + "/proj", "proj", datetime.now())
        
        assert result.success is False

    @patch('backend.services.git_sync_service.Repo')
    def test_pull_git_error(self, mock_repo):
        """测试拉取Git错误"""
        from backend.services.git_sync_service import GitSyncService
        import tempfile
        temp = tempfile.mkdtemp()
        
        mock_git_repo = Mock()
        mock_git_repo.remotes.origin.fetch.side_effect = Exception("Fetch failed")
        mock_repo.return_value = mock_git_repo
        
        git_dir = os.path.join(temp, ".git")
        os.makedirs(git_dir)
        
        service = GitSyncService(base_path=temp)
        result = service._pull_changes(temp, "proj", datetime.now())
        
        assert result.success is False


class TestOcCollabClientExtra:
    """OcCollabClient 额外测试"""

    @patch('backend.services.oc_collab_client.shutil.which')
    @patch('backend.services.oc_collab_client.subprocess.run')
    def test_call_cli_timeout(self, mock_run, mock_which):
        """测试CLI超时"""
        from backend.services.oc_collab_client import OcCollabClient, OcCollabTimeoutError
        import subprocess
        
        mock_which.return_value = "/usr/bin/oc-collab"
        mock_run.side_effect = subprocess.TimeoutExpired("cmd", 30)
        
        client = OcCollabClient()
        
        with pytest.raises(OcCollabTimeoutError):
            client._call_cli(['project', 'test', 'status'])

    @patch('backend.services.oc_collab_client.shutil.which')
    @patch('backend.services.oc_collab_client.subprocess.run')
    def test_call_cli_not_found(self, mock_run, mock_which):
        """测试CLI未找到"""
        from backend.services.oc_collab_client import OcCollabClient, OcCollabNotFoundError
        
        mock_which.return_value = None
        
        client = OcCollabClient()
        
        with pytest.raises(OcCollabNotFoundError):
            client._call_cli(['project', 'test', 'status'])

    @patch('backend.services.oc_collab_client.shutil.which')
    @patch('backend.services.oc_collab_client.subprocess.run')
    def test_call_cli_parse_error(self, mock_run, mock_which):
        """测试JSON解析错误"""
        from backend.services.oc_collab_client import OcCollabClient, OcCollabParseError
        import json
        
        mock_which.return_value = "/usr/bin/oc-collab"
        
        mock_result = Mock()
        mock_result.returncode = 0
        mock_result.stdout = 'invalid json {'
        mock_result.stderr = ''
        mock_run.return_value = mock_result
        
        client = OcCollabClient()
        
        with pytest.raises(OcCollabParseError):
            client._call_cli(['project', 'test', 'status'])


class TestStatusFeedbackServiceExtra:
    """StatusFeedbackService 额外测试"""

    def test_change_event_full(self):
        """测试完整变更事件"""
        from backend.services.status_feedback_service import ChangeEvent, ChangeType
        
        event = ChangeEvent(
            project_name="test",
            change_type=ChangeType.REQUIREMENT,
            change_id="REQ-001",
            title="New requirement",
            old_status="draft",
            new_status="proposed",
            old_value="10",
            new_value="20",
            description="Test description",
            changed_at=datetime.now(),
            source="manual"
        )
        
        assert event.change_type == ChangeType.REQUIREMENT
        assert event.old_value == "10"

    def test_callback_multiple(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",
            change_type=ChangeType.TODO,
            change_id="TODO-001",
            title="Test",
            old_status="pending",
            new_status="completed"
        )
        
        service._notify_callbacks(event)
        
        assert call_count[0] == 2


class TestProgressServiceExtra:
    """ProgressService 额外测试"""

    def test_progress_full(self):
        """测试完整进度数据"""
        from backend.services.progress_service import ProjectProgress, RequirementsProgress, BugsProgress, TodosProgress
        
        progress = ProjectProgress(
            project_name="test",
            overall_progress=75,
            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),
            updated_at=datetime.now()
        )
        
        assert progress.overall_progress == 75
        assert progress.requirements.completed == 8


class TestIssueSyncServiceExtra:
    """IssueSyncService 额外测试"""

    def test_sync_bug_full(self):
        """测试完整BUG同步"""
        from backend.services.issue_sync_service import SyncBug
        
        bug = SyncBug(
            id="BUG-001",
            title="Test bug",
            status="resolved",
            severity="high",
            description="Test description",
            assignee="John",
            created_at=datetime.now(),
            resolved_at=datetime.now()
        )
        
        assert bug.status == "resolved"
        assert bug.severity == "high"

    def test_sync_requirement_full(self):
        """测试完整需求同步"""
        from backend.services.issue_sync_service import SyncRequirement
        
        req = SyncRequirement(
            id="REQ-001",
            title="Test requirement",
            status="implemented",
            priority="high",
            background="Test background",
            user_scenario="As a user...",
            expected_behavior="System should...",
            estimated_hours=8.5,
            created_at=datetime.now(),
            implemented_at=datetime.now()
        )
        
        assert req.status == "implemented"
        assert req.estimated_hours == 8.5


class TestDocumentFetcherExtra:
    """DocumentFetcher 额外测试"""

    def test_document_full(self):
        """测试完整文档"""
        from backend.services.document_fetcher import Document
        
        doc = Document(
            name="README.md",
            path="docs/README.md",
            category="文档",
            file_type="md",
            size=1024,
            content="# Test",
            modified_at=datetime.now()
        )
        
        assert doc.name == "README.md"
        assert doc.size == 1024

    def test_category(self):
        """测试文档分类"""
        from backend.services.document_fetcher import DocumentCategory
        
        cat = DocumentCategory(name="源代码", path="src", document_count=5)
        
        assert cat.document_count == 5


class TestConfidentialExtra:
    """保密功能 额外测试"""

    def test_sensitive_file(self):
        """测试敏感文件"""
        from backend.services.confidential_checker import SensitiveFile
        
        sf = SensitiveFile(
            path="/test/secret.txt",
            matched_keywords=["secret"],
            line_numbers=[10, 20],
            suggestion="Remove secret"
        )
        
        assert sf.suggestion == "Remove secret"

    def test_check_result(self):
        """测试检查结果"""
        from backend.services.confidential_checker import SensitiveCheckResult
        
        result = SensitiveCheckResult(
            has_sensitive=True,
            files_count=2,
            files=[],
            warning_message="Found sensitive",
            blocked=True
        )
        
        assert result.blocked is True


class TestSyncPermissionExtra:
    """同步权限 额外测试"""

    def test_permission_full(self):
        """测试完整权限"""
        from backend.services.sync_permission_service import SyncPermission
        
        perm = SyncPermission(
            allowed=True,
            reason="Normal project",
            requires_confirmation=False,
            warnings=["Warning 1"]
        )
        
        assert perm.warnings[0] == "Warning 1"


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