"""
Test Milestone 18: Jira Signal Agent.
Seeds real signals and raises actual Jira tickets.
Requires Milestone 17 (Jira client) to be passing.
"""
import asyncio
import os
import sys
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))


# ─── Sample signals ───────────────────────────────────────────────────────────

SAMPLE_SIGNALS = [
    {
        "id": "test-signal-001",
        "type": "recurring_bug",
        "summary": "Checkout endpoint hits intermittent timeout — third time this sprint. Restarting the pod is the workaround.",
        "raw_quote": "Sam: Timeout error AGAIN. That's the third time. We have a systemic issue here.",
        "severity": "high",
        "status": "open",
        "sentiment": "negative",
        "urgency": "high",
        "entities": ["@Sam", "@Alex"],
        "keywords": ["timeout", "checkout", "pod", "systemic"],
        "timestamp": "2026-03-21T09:00:00Z",
        "group_id": "acme_dev",
        "lens": "dev",
    },
    {
        "id": "test-signal-002",
        "type": "tech_debt",
        "summary": "JWT secret is hardcoded in auth service. Will move to Vault later, no timeline set.",
        "raw_quote": "Alex: For the auth service, I'm hardcoding the JWT secret for now. We'll move to vault later.",
        "severity": "medium",
        "status": "open",
        "sentiment": "neutral",
        "urgency": "low",
        "entities": ["@Alex"],
        "keywords": ["jwt", "hardcode", "vault", "auth", "secret"],
        "timestamp": "2026-03-21T09:05:00Z",
        "group_id": "acme_dev",
        "lens": "dev",
    },
    {
        "id": "test-signal-003",
        "type": "meet_blocker",
        "summary": "Dashboard spec has been blocked waiting on design for two weeks. Dev cannot start work.",
        "raw_quote": "Alex: Still no dashboard specs from design. This is blocking my entire sprint work.",
        "severity": "high",
        "status": "open",
        "sentiment": "negative",
        "urgency": "high",
        "entities": ["@Alex", "@design"],
        "keywords": ["dashboard", "blocked", "design", "specs", "sprint"],
        "timestamp": "2026-03-21T10:00:00Z",
        "group_id": "meet_sessions",
        "lens": "meet",
        "meeting_id": "sprint-planning-test",
    },
]

# A signal type that should NOT be raised (raw chunk is not a raiseable type)
NON_RAISEABLE_SIGNAL = {
    "id": "test-signal-999",
    "type": "meet_chunk_raw",
    "summary": "Raw transcript chunk — should not be raised as a ticket",
    "raw_quote": "...",
    "severity": "low",
    "status": "open",
    "sentiment": "neutral",
    "urgency": "none",
    "entities": [],
    "keywords": [],
    "timestamp": "2026-03-21T10:00:00Z",
    "group_id": "meet_sessions",
    "lens": "meet",
}


async def test_ticket_generation():
    """Test that LLM generates a valid ticket from a signal."""
    from backend.agents.jira_agent import generate_ticket_content

    print("Testing LLM ticket content generation...")
    signal = SAMPLE_SIGNALS[0]  # recurring_bug
    content = await generate_ticket_content(signal)

    assert "summary" in content and len(content["summary"]) > 5, "Summary too short or missing"
    assert len(content["summary"]) <= 100, f"Summary exceeds 100 chars: {len(content['summary'])}"
    assert "description" in content and len(content["description"]) > 30, "Description too short"
    assert "labels" in content and "thirdeye" in content["labels"], "Missing 'thirdeye' label"
    assert "assignee_name" in content  # can be None, that's fine

    print(f"  ✅ Summary ({len(content['summary'])} chars): {content['summary']}")
    print(f"  ✅ Description ({len(content['description'])} chars)")
    print(f"  ✅ Labels: {content['labels']}")
    print(f"  ✅ Assignee hint: {content.get('assignee_name')}")


async def test_raise_single_ticket():
    """Test raising a single ticket for a real signal."""
    from backend.agents.jira_agent import raise_ticket_for_signal

    print("\nTesting raise_ticket_for_signal()...")
    signal = SAMPLE_SIGNALS[0]  # recurring_bug, high severity
    group_id = "test_jira_m18"

    result = await raise_ticket_for_signal(signal, group_id, force=True)

    assert result.get("ok"), f"raise_ticket_for_signal failed: {result}"
    print(f"  ✅ Ticket raised: {result['key']}")
    print(f"     URL: {result['url']}")
    print(f"     Type: {result['issue_type']} | Priority: {result['priority']}")
    print(f"     Summary: {result['summary'][:90]}")
    return result["key"]


async def test_dedup_prevents_double_raise():
    """Test that the same signal cannot be raised twice."""
    from backend.agents.jira_agent import raise_ticket_for_signal
    from backend.db.chroma import mark_signal_as_raised

    print("\nTesting dedup — cannot raise the same signal twice...")
    signal = SAMPLE_SIGNALS[1]  # tech_debt
    group_id = "test_jira_m18_dedup"

    # First raise
    result1 = await raise_ticket_for_signal(signal, group_id, force=True)
    assert result1.get("ok"), f"First raise failed: {result1}"
    print(f"  ✅ First raise succeeded: {result1['key']}")

    # Second raise of the same signal — should be blocked
    result2 = await raise_ticket_for_signal(signal, group_id, force=False)
    assert not result2.get("ok"), "Expected second raise to be blocked"
    assert result2.get("reason") == "already_raised", f"Expected 'already_raised', got: {result2.get('reason')}"
    print(f"  ✅ Second raise correctly blocked: reason='{result2['reason']}'")


async def test_non_raiseable_signal():
    """Test that non-raiseable signal types are rejected."""
    from backend.agents.jira_agent import raise_ticket_for_signal

    print("\nTesting non-raiseable signal type rejection...")
    result = await raise_ticket_for_signal(NON_RAISEABLE_SIGNAL, "test_group", force=True)
    assert not result.get("ok")
    assert result.get("reason") == "not_raiseable"
    print(f"  ✅ Non-raiseable type correctly rejected: {NON_RAISEABLE_SIGNAL['type']}")


async def test_bulk_raise():
    """Test bulk raising multiple signals at once."""
    from backend.agents.jira_agent import bulk_raise_for_group

    print("\nTesting bulk_raise_for_group()...")
    group_id = "test_jira_m18_bulk"

    # Mix of raiseable and non-raiseable, different severities
    all_signals = SAMPLE_SIGNALS + [NON_RAISEABLE_SIGNAL]
    results = await bulk_raise_for_group(
        group_id=group_id,
        signals=all_signals,
        min_severity="medium",  # low severity signals should be skipped
        max_tickets=5,
    )

    raised = [r for r in results if r.get("ok")]
    skipped_type = [r for r in results if r.get("reason") == "not_raiseable"]

    assert len(raised) >= 1, "Expected at least 1 ticket raised from bulk"
    print(f"  ✅ Bulk raised {len(raised)} ticket(s) from {len(all_signals)} signals")
    for r in raised:
        print(f"     [{r['key']}] {r.get('signal_type')} — {r.get('signal_summary', '')[:60]}")
    if skipped_type:
        print(f"  ✅ {len(skipped_type)} non-raiseable signal(s) correctly skipped")


async def test_priority_mapping():
    """Test that signal severity maps to correct Jira priority."""
    from backend.agents.jira_agent import SEVERITY_TO_PRIORITY, SIGNAL_TYPE_MAP

    print("\nTesting priority and type mapping...")
    assert SEVERITY_TO_PRIORITY["critical"] == "Highest"
    assert SEVERITY_TO_PRIORITY["high"] == "High"
    assert SEVERITY_TO_PRIORITY["medium"] == "Medium"
    assert SEVERITY_TO_PRIORITY["low"] == "Low"
    print("  ✅ Severity → Priority mapping correct")

    assert SIGNAL_TYPE_MAP["recurring_bug"] == ("Task", "High")
    assert SIGNAL_TYPE_MAP["meet_blocker"] == ("Task", "Highest")
    assert SIGNAL_TYPE_MAP["feature_request"] == ("Task", "Medium")
    print("  ✅ Signal type → Jira type mapping correct")


async def main():
    print("Running Milestone 18 tests...\n")
    await test_priority_mapping()
    await test_ticket_generation()
    key = await test_raise_single_ticket()
    await test_dedup_prevents_double_raise()
    await test_non_raiseable_signal()
    await test_bulk_raise()
    print(f"\n🎉 MILESTONE 18 PASSED — Jira Signal Agent working. First ticket: {key}")


asyncio.run(main())