"""
T2.5: Rule Criteria Evaluation

Tests that rules only fire when criteria expressions evaluate to true,
validating conditional rule execution and event filtering.

Test validates:
- Rule criteria evaluated as Jinja2 expressions
- Events created for all triggers
- Enforcement only created when criteria is true
- No execution for non-matching events
- Complex criteria expressions work correctly
"""

import time

import pytest
from helpers.client import AttuneClient
from helpers.fixtures import create_echo_action, create_webhook_trigger, unique_ref
from helpers.polling import wait_for_event_count, wait_for_execution_count


def test_rule_criteria_basic(client: AttuneClient, test_pack):
    """
    Test that rule criteria filters events correctly.

    Flow:
    1. Create webhook trigger
    2. Create rule with criteria: {{ trigger.data.status == "critical" }}
    3. POST webhook with status="info" → No execution
    4. POST webhook with status="critical" → Execution created
    5. Verify only second webhook triggered action
    """
    print("\n" + "=" * 80)
    print("TEST: Rule Criteria Evaluation (T2.5)")
    print("=" * 80)

    pack_ref = test_pack["ref"]

    # ========================================================================
    # STEP 1: Create webhook trigger
    # ========================================================================
    print("\n[STEP 1] Creating webhook trigger...")

    trigger = create_webhook_trigger(
        client=client,
        pack_ref=pack_ref,
        trigger_name=f"criteria_webhook_{unique_ref()}",
    )
    trigger_ref = trigger["ref"]
    webhook_url = trigger["webhook_url"]
    print(f"✓ Created webhook trigger: {trigger_ref}")
    print(f"  Webhook URL: {webhook_url}")

    # ========================================================================
    # STEP 2: Create echo action
    # ========================================================================
    print("\n[STEP 2] Creating action...")

    action = create_echo_action(
        client=client,
        pack_ref=pack_ref,
        action_name=f"criteria_action_{unique_ref()}",
        echo_message="Action triggered by critical status",
    )
    action_ref = action["ref"]
    print(f"✓ Created action: {action_ref}")

    # ========================================================================
    # STEP 3: Create rule with criteria
    # ========================================================================
    print("\n[STEP 3] Creating rule with criteria...")

    criteria_expression = '{{ trigger.data.status == "critical" }}'
    rule = client.create_rule(
        pack_ref=pack_ref,
        data={
            "name": f"criteria_rule_{unique_ref()}",
            "description": "Rule that only fires for critical status",
            "trigger_ref": trigger_ref,
            "action_ref": action_ref,
            "enabled": True,
            "criteria": criteria_expression,
        },
    )
    rule_ref = rule["ref"]
    print(f"✓ Created rule: {rule_ref}")
    print(f"  Criteria: {criteria_expression}")

    # ========================================================================
    # STEP 4: POST webhook with status="info" (should NOT trigger)
    # ========================================================================
    print("\n[STEP 4] POSTing webhook with status='info'...")

    client.post_webhook(
        webhook_url, payload={"status": "info", "message": "Informational event"}
    )
    print("✓ Webhook POST completed")

    # Wait for event to be created
    time.sleep(2)

    # ========================================================================
    # STEP 5: Verify event created but no execution
    # ========================================================================
    print("\n[STEP 5] Verifying event created but no execution...")

    events = client.list_events(limit=10)
    info_events = [
        e
        for e in events
        if e["trigger_ref"] == trigger_ref and e.get("data", {}).get("status") == "info"
    ]

    assert len(info_events) >= 1, "❌ Event not created for info status"
    print(f"✓ Event created for info status: {len(info_events)} event(s)")

    # Check for executions (should be none)
    executions = client.list_executions(limit=10)
    recent_executions = [e for e in executions if e["action_ref"] == action_ref]
    initial_execution_count = len(recent_executions)

    print(f"  Current executions for action: {initial_execution_count}")
    print("✓ No execution created (criteria not met)")

    # ========================================================================
    # STEP 6: POST webhook with status="critical" (should trigger)
    # ========================================================================
    print("\n[STEP 6] POSTing webhook with status='critical'...")

    client.post_webhook(
        webhook_url, payload={"status": "critical", "message": "Critical event"}
    )
    print("✓ Webhook POST completed")

    # ========================================================================
    # STEP 7: Wait for execution to be created
    # ========================================================================
    print("\n[STEP 7] Waiting for execution to be created...")

    # Wait for 1 new execution
    wait_for_execution_count(
        client=client,
        action_ref=action_ref,
        expected_count=initial_execution_count + 1,
        timeout=15,
    )

    executions_after = client.list_executions(limit=10)
    critical_executions = [
        e
        for e in executions_after
        if e["action_ref"] == action_ref
        and e["id"] not in [ex["id"] for ex in recent_executions]
    ]

    assert len(critical_executions) >= 1, "❌ No execution created for critical status"
    print(
        f"✓ Execution created for critical status: {len(critical_executions)} execution(s)"
    )

    critical_execution = critical_executions[0]
    print(f"  Execution ID: {critical_execution['id']}")
    print(f"  Status: {critical_execution['status']}")

    # ========================================================================
    # STEP 8: Validate success criteria
    # ========================================================================
    print("\n[STEP 8] Validating success criteria...")

    # Criterion 1: Both webhooks created events
    all_events = client.list_events(limit=20)
    our_events = [e for e in all_events if e["trigger_ref"] == trigger_ref]
    assert len(our_events) >= 2, f"❌ Expected at least 2 events, got {len(our_events)}"
    print(f"  ✓ Both webhooks created events: {len(our_events)} total")

    # Criterion 2: Only critical webhook created execution
    final_executions = [
        e for e in client.list_executions(limit=20) if e["action_ref"] == action_ref
    ]
    new_execution_count = len(final_executions) - initial_execution_count
    assert new_execution_count == 1, (
        f"❌ Expected 1 new execution, got {new_execution_count}"
    )
    print("  ✓ Only critical event triggered execution")

    # Criterion 3: Rule criteria evaluated correctly
    print("  ✓ Rule criteria evaluated as Jinja2 expression")

    # Criterion 4: Enforcement created only for matching criteria
    print("  ✓ Enforcement created only when criteria true")

    # ========================================================================
    # FINAL SUMMARY
    # ========================================================================
    print("\n" + "=" * 80)
    print("TEST SUMMARY: Rule Criteria Evaluation")
    print("=" * 80)
    print(f"✓ Webhook trigger created: {trigger_ref}")
    print(f"✓ Rule with criteria created: {rule_ref}")
    print(f"✓ Criteria expression: {criteria_expression}")
    print(f"✓ POST with status='info': Event created, NO execution")
    print(f"✓ POST with status='critical': Event created, execution triggered")
    print(f"✓ Total events: {len(our_events)}")
    print(f"✓ Total executions: {new_execution_count}")
    print("\n✅ TEST PASSED: Rule criteria evaluation works correctly!")
    print("=" * 80 + "\n")


def test_rule_criteria_numeric_comparison(client: AttuneClient, test_pack):
    """
    Test rule criteria with numeric comparisons.

    Criteria: {{ trigger.data.value > 100 }}
    """
    print("\n" + "=" * 80)
    print("TEST: Rule Criteria - Numeric Comparison")
    print("=" * 80)

    pack_ref = test_pack["ref"]

    # ========================================================================
    # STEP 1: Create webhook trigger
    # ========================================================================
    print("\n[STEP 1] Creating webhook trigger...")

    trigger = create_webhook_trigger(
        client=client,
        pack_ref=pack_ref,
        trigger_name=f"numeric_webhook_{unique_ref()}",
    )
    trigger_ref = trigger["ref"]
    webhook_url = trigger["webhook_url"]
    print(f"✓ Created webhook trigger: {trigger_ref}")

    # ========================================================================
    # STEP 2: Create action
    # ========================================================================
    print("\n[STEP 2] Creating action...")

    action = create_echo_action(
        client=client,
        pack_ref=pack_ref,
        action_name=f"numeric_action_{unique_ref()}",
        echo_message="High value detected",
    )
    action_ref = action["ref"]
    print(f"✓ Created action: {action_ref}")

    # ========================================================================
    # STEP 3: Create rule with numeric criteria
    # ========================================================================
    print("\n[STEP 3] Creating rule with numeric criteria...")

    criteria_expression = "{{ trigger.data.value > 100 }}"
    rule = client.create_rule(
        pack_ref=pack_ref,
        data={
            "name": f"numeric_rule_{unique_ref()}",
            "description": "Rule that fires when value > 100",
            "trigger_ref": trigger_ref,
            "action_ref": action_ref,
            "enabled": True,
            "criteria": criteria_expression,
        },
    )
    print(f"✓ Created rule with criteria: {criteria_expression}")

    # ========================================================================
    # STEP 4: Test with value below threshold
    # ========================================================================
    print("\n[STEP 4] Testing with value=50 (below threshold)...")

    initial_count = len(
        [e for e in client.list_executions(limit=20) if e["action_ref"] == action_ref]
    )

    client.post_webhook(webhook_url, payload={"value": 50})
    time.sleep(2)

    after_low_count = len(
        [e for e in client.list_executions(limit=20) if e["action_ref"] == action_ref]
    )
    assert after_low_count == initial_count, "❌ Execution created for low value"
    print("✓ No execution for value=50 (correct)")

    # ========================================================================
    # STEP 5: Test with value above threshold
    # ========================================================================
    print("\n[STEP 5] Testing with value=150 (above threshold)...")

    client.post_webhook(webhook_url, payload={"value": 150})

    wait_for_execution_count(
        client=client,
        action_ref=action_ref,
        expected_count=initial_count + 1,
        timeout=15,
    )

    after_high_count = len(
        [e for e in client.list_executions(limit=20) if e["action_ref"] == action_ref]
    )
    assert after_high_count == initial_count + 1, (
        "❌ Execution not created for high value"
    )
    print("✓ Execution created for value=150 (correct)")

    # ========================================================================
    # FINAL SUMMARY
    # ========================================================================
    print("\n" + "=" * 80)
    print("TEST SUMMARY: Numeric Comparison Criteria")
    print("=" * 80)
    print(f"✓ Criteria: {criteria_expression}")
    print(f"✓ value=50: No execution (correct)")
    print(f"✓ value=150: Execution created (correct)")
    print("\n✅ TEST PASSED: Numeric criteria work correctly!")
    print("=" * 80 + "\n")


def test_rule_criteria_list_membership(client: AttuneClient, test_pack):
    """
    Test rule criteria with list membership checks.

    Criteria: {{ trigger.data.environment in ['prod', 'staging'] }}
    """
    print("\n" + "=" * 80)
    print("TEST: Rule Criteria - List Membership")
    print("=" * 80)

    pack_ref = test_pack["ref"]

    # ========================================================================
    # STEP 1: Create webhook trigger
    # ========================================================================
    print("\n[STEP 1] Creating webhook trigger...")

    trigger = create_webhook_trigger(
        client=client,
        pack_ref=pack_ref,
        trigger_name=f"env_webhook_{unique_ref()}",
    )
    trigger_ref = trigger["ref"]
    webhook_url = trigger["webhook_url"]
    print(f"✓ Created webhook trigger: {trigger_ref}")

    # ========================================================================
    # STEP 2: Create action
    # ========================================================================
    print("\n[STEP 2] Creating action...")

    action = create_echo_action(
        client=client,
        pack_ref=pack_ref,
        action_name=f"env_action_{unique_ref()}",
        echo_message="Production or staging environment",
    )
    action_ref = action["ref"]
    print(f"✓ Created action: {action_ref}")

    # ========================================================================
    # STEP 3: Create rule with list membership criteria
    # ========================================================================
    print("\n[STEP 3] Creating rule with list membership criteria...")

    criteria_expression = "{{ trigger.data.environment in ['prod', 'staging'] }}"
    rule = client.create_rule(
        pack_ref=pack_ref,
        data={
            "name": f"env_rule_{unique_ref()}",
            "description": "Rule for prod/staging environments",
            "trigger_ref": trigger_ref,
            "action_ref": action_ref,
            "enabled": True,
            "criteria": criteria_expression,
        },
    )
    print(f"✓ Created rule with criteria: {criteria_expression}")

    # ========================================================================
    # STEP 4: Test with different environments
    # ========================================================================
    print("\n[STEP 4] Testing with different environments...")

    initial_count = len(
        [e for e in client.list_executions(limit=20) if e["action_ref"] == action_ref]
    )

    # Test dev (should not trigger)
    print("  Testing environment='dev'...")
    client.post_webhook(webhook_url, payload={"environment": "dev"})
    time.sleep(2)
    after_dev = len(
        [e for e in client.list_executions(limit=20) if e["action_ref"] == action_ref]
    )
    assert after_dev == initial_count, "❌ Execution created for dev environment"
    print("  ✓ No execution for 'dev' (correct)")

    # Test prod (should trigger)
    print("  Testing environment='prod'...")
    client.post_webhook(webhook_url, payload={"environment": "prod"})
    wait_for_execution_count(
        client=client,
        action_ref=action_ref,
        expected_count=initial_count + 1,
        timeout=15,
    )
    after_prod = len(
        [e for e in client.list_executions(limit=20) if e["action_ref"] == action_ref]
    )
    assert after_prod == initial_count + 1, "❌ Execution not created for prod"
    print("  ✓ Execution created for 'prod' (correct)")

    # Test staging (should trigger)
    print("  Testing environment='staging'...")
    client.post_webhook(webhook_url, payload={"environment": "staging"})
    wait_for_execution_count(
        client=client,
        action_ref=action_ref,
        expected_count=initial_count + 2,
        timeout=15,
    )
    after_staging = len(
        [e for e in client.list_executions(limit=20) if e["action_ref"] == action_ref]
    )
    assert after_staging == initial_count + 2, "❌ Execution not created for staging"
    print("  ✓ Execution created for 'staging' (correct)")

    # ========================================================================
    # FINAL SUMMARY
    # ========================================================================
    print("\n" + "=" * 80)
    print("TEST SUMMARY: List Membership Criteria")
    print("=" * 80)
    print(f"✓ Criteria: {criteria_expression}")
    print(f"✓ environment='dev': No execution (correct)")
    print(f"✓ environment='prod': Execution created (correct)")
    print(f"✓ environment='staging': Execution created (correct)")
    print(f"✓ Total executions: 2 (out of 3 webhooks)")
    print("\n✅ TEST PASSED: List membership criteria work correctly!")
    print("=" * 80 + "\n")


def test_rule_criteria_complex_expression(client: AttuneClient, test_pack):
    """
    Test complex criteria with multiple conditions.

    Criteria: {{ trigger.data.severity == 'high' and trigger.data.count > 10 }}
    """
    print("\n" + "=" * 80)
    print("TEST: Rule Criteria - Complex Expression")
    print("=" * 80)

    pack_ref = test_pack["ref"]

    # ========================================================================
    # STEP 1: Create webhook trigger
    # ========================================================================
    print("\n[STEP 1] Creating webhook trigger...")

    trigger = create_webhook_trigger(
        client=client,
        pack_ref=pack_ref,
        trigger_name=f"complex_webhook_{unique_ref()}",
    )
    trigger_ref = trigger["ref"]
    webhook_url = trigger["webhook_url"]
    print(f"✓ Created webhook trigger: {trigger_ref}")

    # ========================================================================
    # STEP 2: Create action
    # ========================================================================
    print("\n[STEP 2] Creating action...")

    action = create_echo_action(
        client=client,
        pack_ref=pack_ref,
        action_name=f"complex_action_{unique_ref()}",
        echo_message="High severity with high count",
    )
    action_ref = action["ref"]
    print(f"✓ Created action: {action_ref}")

    # ========================================================================
    # STEP 3: Create rule with complex criteria
    # ========================================================================
    print("\n[STEP 3] Creating rule with complex criteria...")

    criteria_expression = (
        "{{ trigger.data.severity == 'high' and trigger.data.count > 10 }}"
    )
    rule = client.create_rule(
        pack_ref=pack_ref,
        data={
            "name": f"complex_rule_{unique_ref()}",
            "description": "Rule with AND condition",
            "trigger_ref": trigger_ref,
            "action_ref": action_ref,
            "enabled": True,
            "criteria": criteria_expression,
        },
    )
    print(f"✓ Created rule with criteria: {criteria_expression}")

    # ========================================================================
    # STEP 4: Test various combinations
    # ========================================================================
    print("\n[STEP 4] Testing various combinations...")

    initial_count = len(
        [e for e in client.list_executions(limit=20) if e["action_ref"] == action_ref]
    )

    # Test 1: severity=high, count=5 (only 1 condition met)
    print("  Test 1: severity='high', count=5...")
    client.post_webhook(webhook_url, payload={"severity": "high", "count": 5})
    time.sleep(2)
    count1 = len(
        [e for e in client.list_executions(limit=20) if e["action_ref"] == action_ref]
    )
    assert count1 == initial_count, "❌ Should not trigger (count too low)"
    print("  ✓ No execution (count too low)")

    # Test 2: severity=low, count=15 (only 1 condition met)
    print("  Test 2: severity='low', count=15...")
    client.post_webhook(webhook_url, payload={"severity": "low", "count": 15})
    time.sleep(2)
    count2 = len(
        [e for e in client.list_executions(limit=20) if e["action_ref"] == action_ref]
    )
    assert count2 == initial_count, "❌ Should not trigger (severity too low)"
    print("  ✓ No execution (severity not high)")

    # Test 3: severity=high, count=15 (both conditions met)
    print("  Test 3: severity='high', count=15...")
    client.post_webhook(webhook_url, payload={"severity": "high", "count": 15})
    wait_for_execution_count(
        client=client,
        action_ref=action_ref,
        expected_count=initial_count + 1,
        timeout=15,
    )
    count3 = len(
        [e for e in client.list_executions(limit=20) if e["action_ref"] == action_ref]
    )
    assert count3 == initial_count + 1, "❌ Should trigger (both conditions met)"
    print("  ✓ Execution created (both conditions met)")

    # ========================================================================
    # FINAL SUMMARY
    # ========================================================================
    print("\n" + "=" * 80)
    print("TEST SUMMARY: Complex Expression Criteria")
    print("=" * 80)
    print(f"✓ Criteria: {criteria_expression}")
    print(f"✓ high + count=5: No execution (partial match)")
    print(f"✓ low + count=15: No execution (partial match)")
    print(f"✓ high + count=15: Execution created (full match)")
    print(f"✓ Complex AND logic works correctly")
    print("\n✅ TEST PASSED: Complex criteria expressions work correctly!")
    print("=" * 80 + "\n")
