#!/usr/bin/env python3
"""
T1.4: Webhook Trigger with Payload

Tests that a webhook POST triggers an action with payload data.

Test Flow:
1. Create webhook trigger (generates unique URL)
2. Create action that echoes webhook payload
3. Create rule linking webhook → action
4. POST JSON payload to webhook URL
5. Verify event created with correct payload
6. Verify execution receives payload as parameters
7. Verify action output includes webhook data

Success Criteria:
- Webhook trigger generates unique URL (/api/v1/webhooks/{trigger_id})
- POST to webhook creates event immediately
- Event payload matches POST body
- Rule evaluates and creates enforcement
- Execution receives webhook data as input
- Action can access webhook payload fields
"""

import time

import pytest
from helpers import (
    AttuneClient,
    create_echo_action,
    create_rule,
    create_webhook_trigger,
    wait_for_event_count,
    wait_for_execution_count,
    wait_for_execution_status,
)


@pytest.mark.tier1
@pytest.mark.webhook
@pytest.mark.integration
@pytest.mark.timeout(30)
class TestWebhookTrigger:
    """Test webhook trigger automation flow"""

    def test_webhook_trigger_with_payload(self, client: AttuneClient, pack_ref: str):
        """Test that webhook POST triggers action with payload"""

        print(f"\n=== T1.4: Webhook Trigger with Payload ===")

        # Step 1: Create webhook trigger
        print("\n[1/6] Creating webhook trigger...")
        trigger = create_webhook_trigger(client=client, pack_ref=pack_ref)
        print(f"✓ Created trigger: {trigger['label']} (ID: {trigger['id']})")
        print(f"  Ref: {trigger['ref']}")
        print(f"  Webhook URL: /api/v1/webhooks/{trigger['id']}")
        assert "webhook" in trigger["ref"].lower() or trigger.get(
            "webhook_enabled", False
        )

        # Step 2: Create echo action
        print("\n[2/6] Creating echo action...")
        action = create_echo_action(client=client, pack_ref=pack_ref)
        action_ref = action["ref"]
        print(f"✓ Created action: {action_ref} (ID: {action['id']})")

        # Step 3: Create rule linking webhook → action
        print("\n[3/6] Creating rule...")

        # Capture timestamp before rule creation for filtering
        from datetime import datetime, timezone

        rule_creation_time = datetime.now(timezone.utc).isoformat()

        rule = create_rule(
            client=client,
            trigger_id=trigger["id"],
            action_ref=action_ref,
            pack_ref=pack_ref,
            enabled=True,
            action_parameters={
                "message": "{{ trigger.data.message }}",
                "count": 1,
            },
        )
        print(f"✓ Created rule: {rule['label']} (ID: {rule['id']})")
        print(f"  Rule creation timestamp: {rule_creation_time}")
        assert rule["enabled"] is True

        # Step 4: POST to webhook
        print("\n[4/6] Firing webhook with payload...")
        webhook_payload = {
            "event_type": "test.webhook",
            "message": "Hello from webhook!",
            "user_id": 12345,
            "metadata": {"source": "e2e_test", "timestamp": time.time()},
        }
        print(f"  Payload: {webhook_payload}")

        event_response = client.fire_webhook(
            trigger_id=trigger["id"], payload=webhook_payload
        )
        print(f"✓ Webhook fired")
        print(f"  Event ID: {event_response.get('id')}")

        # Step 5: Verify event created
        print("\n[5/6] Verifying event created...")
        events = wait_for_event_count(
            client=client,
            expected_count=1,
            trigger_id=trigger["id"],
            timeout=10,
            poll_interval=0.5,
        )

        assert len(events) >= 1, "Expected at least 1 event"
        event = events[0]

        print(f"✓ Event created (ID: {event['id']})")
        print(f"  Trigger ID: {event['trigger']}")
        print(f"  Payload: {event.get('payload')}")

        # Verify event payload matches webhook payload
        assert event["trigger"] == trigger["id"]
        event_payload = event.get("payload", {})

        # Check key fields from webhook payload
        for key in ["event_type", "message", "user_id"]:
            assert key in event_payload, f"Missing key '{key}' in event payload"
            assert event_payload[key] == webhook_payload[key], (
                f"Event payload mismatch for '{key}': "
                f"expected {webhook_payload[key]}, got {event_payload[key]}"
            )

        print(f"✓ Event payload matches webhook payload")

        # Step 6: Verify execution completed with webhook data
        print("\n[6/6] Verifying execution with webhook data...")

        executions = wait_for_execution_count(
            client=client,
            expected_count=1,
            rule_id=rule["id"],
            created_after=rule_creation_time,
            timeout=20,
            poll_interval=0.5,
            verbose=True,
        )

        assert len(executions) >= 1, "Expected at least 1 execution"
        execution = executions[0]

        print(f"✓ Execution created (ID: {execution['id']})")
        print(f"  Status: {execution['status']}")

        # Wait for execution to complete
        if execution["status"] not in ["succeeded", "failed", "canceled"]:
            execution = wait_for_execution_status(
                client=client,
                execution_id=execution["id"],
                expected_status="succeeded",
                timeout=15,
            )

        assert execution["status"] == "succeeded", (
            f"Execution failed with status: {execution['status']}"
        )

        # Verify execution received webhook data
        print(f"\n  Execution details:")
        print(f"    Action: {execution['action_ref']}")
        print(f"    Parameters: {execution.get('parameters')}")
        print(f"    Result: {execution.get('result')}")

        # Final summary
        print("\n=== Test Summary ===")
        print(f"✓ Webhook trigger created")
        print(f"✓ Webhook POST created event")
        print(f"✓ Event payload correct")
        print(f"✓ Execution completed successfully")
        print(f"✓ Webhook data accessible in action")
        print(f"✓ Test PASSED")

    def test_multiple_webhook_posts(self, client: AttuneClient, pack_ref: str):
        """Test multiple webhook POSTs create multiple executions"""

        print(f"\n=== T1.4b: Multiple Webhook POSTs ===")

        num_posts = 3

        # Create automation
        print("\n[1/4] Setting up webhook automation...")
        from datetime import datetime, timezone

        test_start = datetime.now(timezone.utc).isoformat()

        trigger = create_webhook_trigger(client=client, pack_ref=pack_ref)
        action = create_echo_action(client=client, pack_ref=pack_ref)
        rule = create_rule(
            client=client,
            trigger_id=trigger["id"],
            action_ref=action["ref"],
            pack_ref=pack_ref,
        )
        print(f"✓ Setup complete")

        # Fire webhook multiple times
        print(f"\n[2/4] Firing webhook {num_posts} times...")
        for i in range(num_posts):
            payload = {
                "iteration": i + 1,
                "message": f"Webhook post #{i + 1}",
                "timestamp": time.time(),
            }
            client.fire_webhook(trigger_id=trigger["id"], payload=payload)
            print(f"  ✓ POST {i + 1}/{num_posts}")
            time.sleep(0.5)  # Small delay between posts

        # Verify events created
        print(f"\n[3/4] Verifying {num_posts} events created...")
        events = wait_for_event_count(
            client=client,
            expected_count=num_posts,
            trigger_id=trigger["id"],
            timeout=15,
            poll_interval=0.5,
        )

        print(f"✓ {len(events)} events created")
        assert len(events) >= num_posts

        # Verify executions created
        print(f"\n[4/4] Verifying {num_posts} executions completed...")
        executions = wait_for_execution_count(
            client=client,
            expected_count=num_posts,
            rule_id=rule["id"],
            created_after=test_start,
            timeout=20,
            poll_interval=0.5,
            verbose=True,
        )

        print(f"✓ {len(executions)} executions created")

        # Wait for all to complete
        succeeded = 0
        for execution in executions[:num_posts]:
            if execution["status"] not in ["succeeded", "failed", "canceled"]:
                execution = wait_for_execution_status(
                    client=client,
                    execution_id=execution["id"],
                    expected_status="succeeded",
                    timeout=10,
                )
            if execution["status"] == "succeeded":
                succeeded += 1

        print(f"✓ {succeeded}/{num_posts} executions succeeded")
        assert succeeded == num_posts

        print("\n=== Test Summary ===")
        print(f"✓ {num_posts} webhook POSTs handled")
        print(f"✓ {num_posts} events created")
        print(f"✓ {num_posts} executions completed")
        print(f"✓ Test PASSED")

    def test_webhook_with_complex_payload(self, client: AttuneClient, pack_ref: str):
        """Test webhook with nested JSON payload"""

        print(f"\n=== T1.4c: Webhook with Complex Payload ===")

        # Setup
        print("\n[1/3] Setting up webhook automation...")
        from datetime import datetime, timezone

        test_start = datetime.now(timezone.utc).isoformat()

        trigger = create_webhook_trigger(client=client, pack_ref=pack_ref)
        action = create_echo_action(client=client, pack_ref=pack_ref)
        rule = create_rule(
            client=client,
            trigger_id=trigger["id"],
            action_ref=action["ref"],
            pack_ref=pack_ref,
        )
        print(f"✓ Setup complete")

        # Complex nested payload
        print("\n[2/3] Posting complex payload...")
        complex_payload = {
            "event": "user.signup",
            "user": {
                "id": 99999,
                "email": "test@example.com",
                "profile": {
                    "name": "Test User",
                    "age": 30,
                    "preferences": {
                        "theme": "dark",
                        "notifications": True,
                    },
                },
                "tags": ["new", "trial", "priority"],
            },
            "metadata": {
                "source": "web",
                "ip": "192.168.1.100",
                "user_agent": "Mozilla/5.0",
            },
            "timestamp": "2024-01-01T00:00:00Z",
        }

        client.fire_webhook(trigger_id=trigger["id"], payload=complex_payload)
        print(f"✓ Complex payload posted")

        # Verify event and execution
        print("\n[3/3] Verifying event and execution...")
        events = wait_for_event_count(
            client=client,
            expected_count=1,
            trigger_id=trigger["id"],
            timeout=10,
        )

        assert len(events) >= 1
        event = events[0]
        event_payload = event.get("payload", {})

        # Verify nested structure preserved
        assert "user" in event_payload
        assert "profile" in event_payload["user"]
        assert "preferences" in event_payload["user"]["profile"]
        assert event_payload["user"]["profile"]["preferences"]["theme"] == "dark"
        assert event_payload["user"]["tags"] == ["new", "trial", "priority"]

        print(f"✓ Complex nested payload preserved")

        # Verify execution
        executions = wait_for_execution_count(
            client=client,
            expected_count=1,
            rule_id=rule["id"],
            created_after=test_start,
            timeout=15,
            verbose=True,
        )

        execution = executions[0]
        if execution["status"] not in ["succeeded", "failed", "canceled"]:
            execution = wait_for_execution_status(
                client=client,
                execution_id=execution["id"],
                expected_status="succeeded",
                timeout=10,
            )

        assert execution["status"] == "succeeded"
        print(f"✓ Execution completed successfully")

        print("\n=== Test Summary ===")
        print(f"✓ Complex nested payload handled")
        print(f"✓ JSON structure preserved")
        print(f"✓ Execution completed")
        print(f"✓ Test PASSED")

    def test_webhook_without_payload(self, client: AttuneClient, pack_ref: str):
        """Test webhook POST without payload (empty body)"""

        print(f"\n=== T1.4d: Webhook without Payload ===")

        # Setup
        from datetime import datetime, timezone

        test_start = datetime.now(timezone.utc).isoformat()

        trigger = create_webhook_trigger(client=client, pack_ref=pack_ref)
        action = create_echo_action(client=client, pack_ref=pack_ref)
        rule = create_rule(
            client=client,
            trigger_id=trigger["id"],
            action_ref=action["ref"],
            pack_ref=pack_ref,
        )

        # Fire webhook with empty payload
        print("\nFiring webhook with empty payload...")
        client.fire_webhook(trigger_id=trigger["id"], payload={})

        # Verify event created
        events = wait_for_event_count(
            client=client,
            expected_count=1,
            trigger_id=trigger["id"],
            timeout=10,
        )

        assert len(events) >= 1
        event = events[0]
        print(f"✓ Event created with empty payload")

        # Verify execution
        executions = wait_for_execution_count(
            client=client,
            expected_count=1,
            rule_id=rule["id"],
            created_after=test_start,
            timeout=15,
            verbose=True,
        )

        execution = executions[0]
        if execution["status"] not in ["succeeded", "failed", "canceled"]:
            execution = wait_for_execution_status(
                client=client,
                execution_id=execution["id"],
                expected_status="succeeded",
                timeout=10,
            )

        assert execution["status"] == "succeeded"
        print(f"✓ Execution succeeded with empty payload")
        print(f"✓ Test PASSED")
