#!/usr/bin/env python3
"""
AWOOOI Alert Chain Smoke Test (Wave A.6)
=========================================
E2E 驗證告警鏈路完整性

功能:
1. 發送測試告警到 Sentry/SignOz Webhook
2. 驗證 Telegram 通知發送
3. 檢查 Prometheus Metrics
4. 驗證 Incident 建立

用法:
    cd apps/api
    python -m scripts.alert_chain_smoke_test

    # 指定來源
    python -m scripts.alert_chain_smoke_test --source sentry
    python -m scripts.alert_chain_smoke_test --source signoz
    python -m scripts.alert_chain_smoke_test --source all

環境變數:
    AWOOOI_API_URL: API 端點 (預設 http://localhost:8000)
    AWOOOI_METRICS_URL: Metrics 端點 (預設 http://localhost:8000/metrics)

Author: Claude Code
Date: 2026-03-29
ADR: ADR-037 (監控增強架構)
"""

import argparse
import asyncio
import os
import sys
import time
from datetime import datetime
from pathlib import Path

# Add src to path
sys.path.insert(0, str(Path(__file__).parent.parent / "src"))

import httpx

# =============================================================================
# Config (從環境變數讀取，符合首席架構師審查 P0 要求)
# =============================================================================

API_URL = os.environ.get("AWOOOI_API_URL", "http://localhost:8000")
METRICS_URL = os.environ.get("AWOOOI_METRICS_URL", f"{API_URL}/metrics")

# Webhook 端點
SENTRY_WEBHOOK = f"{API_URL}/api/v1/webhooks/sentry/issue"
SIGNOZ_WEBHOOK = f"{API_URL}/api/v1/webhooks/signoz/alert"

# =============================================================================
# Test Payloads
# =============================================================================

SENTRY_TEST_PAYLOAD = {
    "action": "triggered",
    "data": {
        "issue": {
            "id": f"smoke-test-{int(time.time())}",
            "title": "[Smoke Test] Alert Chain Verification",
            "culprit": "alert_chain_smoke_test.py",
            "level": "error",
            "firstSeen": datetime.now().isoformat(),
            "count": 1,
            "project": {"slug": "awoooi-api"},
        },
        "event": {
            "message": "Smoke test alert - verifying alert chain E2E",
            "platform": "python",
            "tags": [{"key": "smoke_test", "value": "true"}],
        },
    },
}

SIGNOZ_TEST_PAYLOAD = {
    "alertname": "SmokeTestAlert",
    "status": "firing",
    "labels": {
        "severity": "warning",
        "service_name": "smoke-test",
        "namespace": "awoooi-test",
        "source": "signoz",
    },
    "annotations": {
        "summary": "[Smoke Test] SignOz Alert Chain Verification",
        "description": "This is a smoke test alert to verify the alert chain E2E",
    },
    "startsAt": datetime.now().isoformat(),
}


# =============================================================================
# Terminal Output Helpers
# =============================================================================

class Colors:
    """ANSI Color Codes"""
    HEADER = "\033[95m"
    BLUE = "\033[94m"
    CYAN = "\033[96m"
    GREEN = "\033[92m"
    YELLOW = "\033[93m"
    RED = "\033[91m"
    ENDC = "\033[0m"
    BOLD = "\033[1m"
    DIM = "\033[2m"


def print_banner():
    """Print banner"""
    print(f"""
{Colors.CYAN}{Colors.BOLD}
  ╔═══════════════════════════════════════════════════════╗
  ║  AWOOOI Alert Chain Smoke Test (ADR-037 Wave A.6)     ║
  ╚═══════════════════════════════════════════════════════╝
{Colors.ENDC}
{Colors.DIM}  API URL: {API_URL}
  Time: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')} (Taipei){Colors.ENDC}
""")


def print_section(title: str):
    """Print section header"""
    print(f"\n{Colors.BLUE}{Colors.BOLD}▶ {title}{Colors.ENDC}")
    print(f"{Colors.DIM}{'─' * 55}{Colors.ENDC}")


def print_result(success: bool, message: str, details: str = ""):
    """Print test result"""
    if success:
        print(f"  {Colors.GREEN}✓ {message}{Colors.ENDC}")
    else:
        print(f"  {Colors.RED}✗ {message}{Colors.ENDC}")
    if details:
        print(f"    {Colors.DIM}{details}{Colors.ENDC}")


# =============================================================================
# Test Functions
# =============================================================================

async def test_sentry_webhook() -> tuple[bool, dict]:
    """
    測試 Sentry Webhook

    Returns:
        (success, response_data)
    """
    print_section("1. Sentry Webhook Test")
    print(f"  {Colors.CYAN}Endpoint:{Colors.ENDC} {SENTRY_WEBHOOK}")

    try:
        async with httpx.AsyncClient(timeout=30.0) as client:
            response = await client.post(
                SENTRY_WEBHOOK,
                json=SENTRY_TEST_PAYLOAD,
                headers={"Content-Type": "application/json"},
            )

            result = response.json()
            success = response.status_code in (200, 202) and result.get("status") in ("accepted", "ok")

            print_result(
                success,
                f"HTTP {response.status_code}",
                f"Response: {result}",
            )

            return success, result

    except httpx.ConnectError:
        print_result(False, "Connection failed", f"Cannot reach {SENTRY_WEBHOOK}")
        return False, {"error": "connection_failed"}
    except Exception as e:
        print_result(False, "Request failed", str(e))
        return False, {"error": str(e)}


async def test_signoz_webhook() -> tuple[bool, dict]:
    """
    測試 SignOz Webhook

    Returns:
        (success, response_data)
    """
    print_section("2. SignOz Webhook Test")
    print(f"  {Colors.CYAN}Endpoint:{Colors.ENDC} {SIGNOZ_WEBHOOK}")

    try:
        async with httpx.AsyncClient(timeout=30.0) as client:
            response = await client.post(
                SIGNOZ_WEBHOOK,
                json=SIGNOZ_TEST_PAYLOAD,
                headers={"Content-Type": "application/json"},
            )

            result = response.json()
            success = response.status_code in (200, 202) and result.get("status") in ("accepted", "ok")

            print_result(
                success,
                f"HTTP {response.status_code}",
                f"Response: {result}",
            )

            return success, result

    except httpx.ConnectError:
        print_result(False, "Connection failed", f"Cannot reach {SIGNOZ_WEBHOOK}")
        return False, {"error": "connection_failed"}
    except Exception as e:
        print_result(False, "Request failed", str(e))
        return False, {"error": str(e)}


async def test_metrics() -> tuple[bool, dict]:
    """
    檢查 Prometheus Metrics

    驗證 Alert Chain 指標存在:
    - awoooi_alert_chain_healthy
    - awoooi_alert_chain_last_success_timestamp
    """
    print_section("3. Prometheus Metrics Check")
    print(f"  {Colors.CYAN}Endpoint:{Colors.ENDC} {METRICS_URL}")

    try:
        async with httpx.AsyncClient(timeout=10.0) as client:
            response = await client.get(METRICS_URL)

            if response.status_code != 200:
                print_result(False, f"HTTP {response.status_code}")
                return False, {"error": f"status_code: {response.status_code}"}

            metrics_text = response.text

            # 檢查必要指標
            required_metrics = [
                "awoooi_alert_chain_healthy",
                "awoooi_alert_chain_last_success_timestamp",
                "awoooi_webhook_requests_total",
                "awoooi_alert_processed_total",
            ]

            found_metrics = {}
            for metric in required_metrics:
                found = metric in metrics_text
                found_metrics[metric] = found
                print_result(found, f"Metric: {metric}")

            all_found = all(found_metrics.values())
            return all_found, found_metrics

    except httpx.ConnectError:
        print_result(False, "Connection failed", f"Cannot reach {METRICS_URL}")
        return False, {"error": "connection_failed"}
    except Exception as e:
        print_result(False, "Request failed", str(e))
        return False, {"error": str(e)}


async def test_health() -> tuple[bool, dict]:
    """
    檢查 API Health
    """
    print_section("4. API Health Check")
    health_url = f"{API_URL}/api/v1/health"
    print(f"  {Colors.CYAN}Endpoint:{Colors.ENDC} {health_url}")

    try:
        async with httpx.AsyncClient(timeout=10.0) as client:
            response = await client.get(health_url)

            success = response.status_code == 200
            result = response.json() if success else {}

            print_result(
                success,
                f"HTTP {response.status_code}",
                f"Status: {result.get('status', 'unknown')}",
            )

            return success, result

    except httpx.ConnectError:
        print_result(False, "Connection failed", f"Cannot reach {health_url}")
        return False, {"error": "connection_failed"}
    except Exception as e:
        print_result(False, "Request failed", str(e))
        return False, {"error": str(e)}


# =============================================================================
# Main
# =============================================================================

async def run_smoke_tests(source: str = "all") -> bool:
    """
    執行 Smoke Tests

    Args:
        source: 測試來源 (sentry, signoz, all)

    Returns:
        bool: 全部通過
    """
    print_banner()

    results = []

    # Health Check
    health_ok, _ = await test_health()
    results.append(("Health", health_ok))

    if not health_ok:
        print(f"\n{Colors.RED}{Colors.BOLD}✗ API 健康檢查失敗，終止測試{Colors.ENDC}")
        return False

    # Webhook Tests
    if source in ("sentry", "all"):
        sentry_ok, _ = await test_sentry_webhook()
        results.append(("Sentry Webhook", sentry_ok))

    if source in ("signoz", "all"):
        signoz_ok, _ = await test_signoz_webhook()
        results.append(("SignOz Webhook", signoz_ok))

    # 等待背景任務處理
    if source != "none":
        print(f"\n{Colors.DIM}  等待 2 秒讓背景任務處理...{Colors.ENDC}")
        await asyncio.sleep(2)

    # Metrics Check
    metrics_ok, _ = await test_metrics()
    results.append(("Metrics", metrics_ok))

    # Summary
    print_section("Summary")
    all_passed = True
    for name, passed in results:
        print_result(passed, name)
        if not passed:
            all_passed = False

    print(f"\n{'─' * 55}")
    if all_passed:
        print(f"{Colors.GREEN}{Colors.BOLD}✓ All smoke tests passed!{Colors.ENDC}")
    else:
        print(f"{Colors.RED}{Colors.BOLD}✗ Some smoke tests failed!{Colors.ENDC}")

    return all_passed


def main():
    """CLI Entry Point"""
    parser = argparse.ArgumentParser(
        description="AWOOOI Alert Chain Smoke Test (ADR-037 Wave A.6)",
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog="""
環境變數:
  AWOOOI_API_URL      API 端點 (預設 http://localhost:8000)
  AWOOOI_METRICS_URL  Metrics 端點 (預設 $AWOOOI_API_URL/metrics)

範例:
  python -m scripts.alert_chain_smoke_test
  python -m scripts.alert_chain_smoke_test --source sentry
  AWOOOI_API_URL=http://awoooi-api:8000 python -m scripts.alert_chain_smoke_test
        """,
    )

    parser.add_argument(
        "--source", "-s",
        type=str,
        default="all",
        choices=["sentry", "signoz", "all", "none"],
        help="測試來源 (預設: all, none = 只檢查 health/metrics)",
    )

    args = parser.parse_args()

    success = asyncio.run(run_smoke_tests(args.source))
    sys.exit(0 if success else 1)


if __name__ == "__main__":
    main()
