import pytest
from opengit.agents import core
import src.mcp.knowledge_graph_mcp as kg_mcp
import src.mcp.claude_analyst_mcp as cl_mcp
import src.mcp.green_optimizer_mcp as go_mcp

class MockProjects:
    def get(self, id):
        class MockProj:
            def __init__(self):
                class MockIssues:
                    def list(self, **kwargs): return []
                self.issues = MockIssues()
        return MockProj()

class MockGL:
    def __init__(self):
        self.projects = MockProjects()

@pytest.mark.asyncio
async def test_doctor_v2_flow_with_mocks(monkeypatch):
    monkeypatch.setenv("OPENGIT_PROJECT", "group/project")
    monkeypatch.setenv("GITLAB_TOKEN", "token")
    monkeypatch.setenv("ANTHROPIC_API_KEY", "mock-key")

    # Mock settings
    class MockSettings:
        gitlab_token = "token"
        @classmethod
        def load(cls): return cls()
    monkeypatch.setattr("opengit.config.Settings", MockSettings)

    # Mock MCP tools
    async def mock_audit(project, ref):
        return [{"scenario": "dependency_drift", "reason": "outdated requests", "package": "requests", "spec": ">=2.31.0"}]

    async def mock_triage(reason, **kwargs):
        return {"learning_moment": "Always pin your deps."}

    async def mock_fix(scenario, content):
        return "requests>=2.31.0\n"

    async def mock_mr_desc(*args):
        return "Rich MR description"

    async def mock_create_branch(*args):
        return {"status": "committed"}

    async def mock_create_incident(*args, **kwargs):
        return {"issue_id": "#123"}

    async def mock_create_mr(*args, **kwargs):
        return {"mr_id": "!456", "url": "http://gitlab.com/mr/456"}

    async def mock_carbon(region):
        return {"intensity": 450, "sci_score": 237.0}

    async def mock_credit(job_type):
        return {"recommendation": "Delay to green window"}

    async def mock_ensure_label(*args, **kwargs):
        return {"status": "exists"}
        
    async def mock_ensure_milestone(*args, **kwargs):
        return {"status": "exists", "id": 1}
        
    async def mock_create_release(*args, **kwargs):
        return {"status": "created"}
        
    async def mock_ensure_badge(*args, **kwargs):
        return {"status": "exists"}

    async def mock_list_group(*args, **kwargs):
        return []

    async def mock_diag_fix(*args, **kwargs):
        return {"status": "no_failures"}
        
    async def mock_resolve_issue(*args, **kwargs):
        return {"status": "skipped"}
        
    async def mock_enforce_bp(*args, **kwargs):
        return {"status": "already_protected"}
        
    async def mock_enforce_ar(*args, **kwargs):
        return {"status": "already_configured"}
        
    async def mock_publish_wiki(*args, **kwargs):
        return {"status": "published"}

    async def mock_track_vsa(*args, **kwargs):
        return {"status": "tracked"}

    async def mock_gen_sec_report(*args, **kwargs):
        return {"report_type": "security", "content": {}, "filename": "gl-sast-report.json"}

    async def mock_enforce_budget(*args, **kwargs):
        return {"status": "ok", "allowed": True}

    # Patch the source modules
    monkeypatch.setattr(kg_mcp, "audit_repository", mock_audit)
    monkeypatch.setattr(kg_mcp, "get_fix_template", mock_fix)
    monkeypatch.setattr(kg_mcp, "create_or_update_file_branch", mock_create_branch)
    monkeypatch.setattr(kg_mcp, "create_incident", mock_create_incident)
    monkeypatch.setattr(kg_mcp, "create_doctor_mr", mock_create_mr)
    
    monkeypatch.setattr(cl_mcp, "triage_failure", mock_triage)
    monkeypatch.setattr(cl_mcp, "generate_mr_description", mock_mr_desc)
    
    monkeypatch.setattr(go_mcp, "get_carbon_intensity", mock_carbon)
    monkeypatch.setattr(go_mcp, "get_credit_optimization_data", mock_credit)
    
    monkeypatch.setattr(kg_mcp, "ensure_label", mock_ensure_label)
    monkeypatch.setattr(kg_mcp, "ensure_milestone", mock_ensure_milestone)
    monkeypatch.setattr(kg_mcp, "create_release", mock_create_release)
    monkeypatch.setattr(kg_mcp, "ensure_badge", mock_ensure_badge)
    monkeypatch.setattr(kg_mcp, "list_group_projects", mock_list_group)
    monkeypatch.setattr(kg_mcp, "diagnose_and_fix_pipeline", mock_diag_fix)
    monkeypatch.setattr(kg_mcp, "resolve_issue_to_mr", mock_resolve_issue)
    monkeypatch.setattr(kg_mcp, "enforce_branch_protection", mock_enforce_bp)
    monkeypatch.setattr(kg_mcp, "enforce_approval_rules", mock_enforce_ar)
    monkeypatch.setattr(kg_mcp, "publish_wiki_report", mock_publish_wiki)
    monkeypatch.setattr(kg_mcp, "track_value_stream", mock_track_vsa)
    monkeypatch.setattr(kg_mcp, "generate_gl_security_report", mock_gen_sec_report)
    monkeypatch.setattr(kg_mcp, "enforce_carbon_budget", mock_enforce_budget)

    # Also patch top-level imports in core.py that might have already happened
    monkeypatch.setattr(core, "get_carbon_intensity", mock_carbon)
    monkeypatch.setattr(core, "get_credit_optimization_data", mock_credit)
    monkeypatch.setattr(core, "_gitlab_client", lambda: MockGL()) # Patch local client too

    logs = []
    def mock_emit(payload):
        logs.append(payload)

    result = await core.run_heartbeat(demo=False, emit=mock_emit)
    
    assert result["status"] == "ok"
    # Verify finding
    scenarios = [l.get("scenario") for l in logs if l.get("scenario")]
    assert "dependency_drift" in scenarios
    
    # Verify green metrics
    sci_scores = [l.get("sci_score") for l in logs if l.get("sci_score") is not None]
    assert 237.0 in sci_scores
