"""
Multi-Sig Redis 自動化測試腳本
==============================
Phase 6.1.1: 全自動單元自檢

測試項目:
1. Redis 連線池初始化
2. 簽核單 CRUD 操作
3. 分散式鎖競爭測試
4. TTL 驗證 (7 天)
5. 雙重簽核防禦

統帥鐵律:
- 禁止人工 QA，此腳本必須全自動執行
- 輸出必須為 Raw Data (stdout logs)
"""

import asyncio
import os
import sys
from datetime import UTC, datetime
from uuid import uuid4

# 添加專案路徑
sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))

import structlog

# 配置 structlog 輸出
structlog.configure(
    processors=[
        structlog.processors.TimeStamper(fmt="iso"),
        structlog.dev.ConsoleRenderer(),
    ],
    wrapper_class=structlog.make_filtering_bound_logger(0),
)

logger = structlog.get_logger(__name__)


async def test_redis_connection():
    """測試 1: Redis 連線池初始化"""
    logger.info("=" * 60)
    logger.info("TEST_1_REDIS_CONNECTION", status="starting")

    from src.core.redis_client import get_redis, init_redis_pool

    try:
        # 初始化連線池
        pool = await init_redis_pool()
        logger.info("redis_pool_initialized", pool_type=type(pool).__name__)

        # 取得連線
        redis_client = get_redis()

        # PING 測試
        pong = await redis_client.ping()
        logger.info("redis_ping", response=pong)

        # 寫入測試值
        test_key = "test:connection:check"
        await redis_client.set(test_key, "awoooi_phase6", ex=60)
        value = await redis_client.get(test_key)
        logger.info("redis_set_get", key=test_key, value=value)

        # 清理測試值
        await redis_client.delete(test_key)

        logger.info("TEST_1_REDIS_CONNECTION", status="PASSED")
        return True

    except Exception as e:
        logger.error("TEST_1_REDIS_CONNECTION", status="FAILED", error=str(e))
        return False


async def test_approval_crud():
    """測試 2: 簽核單 CRUD 操作"""
    logger.info("=" * 60)
    logger.info("TEST_2_APPROVAL_CRUD", status="starting")

    from src.services.multi_sig_redis import get_multi_sig_redis_service

    service = get_multi_sig_redis_service()
    approval_id = str(uuid4())

    try:
        # CREATE
        state = await service.create_approval(
            approval_id=approval_id,
            action="DELETE_POD",
            description="測試簽核單 - Phase 6.1.1 自動化測試",
            risk_level="high",
            required_signatures=2,
            namespace="awoooi",
            resource_name="test-pod-001",
        )
        logger.info("approval_created",
                    id=state["id"],
                    status=state["status"],
                    required=state["required_signatures"])

        # READ
        retrieved = await service.get_approval(approval_id)
        assert retrieved is not None, "Approval not found after create"
        assert retrieved["status"] == "pending", f"Expected pending, got {retrieved['status']}"
        logger.info("approval_retrieved",
                    id=retrieved["id"],
                    signatures_count=len(retrieved["signatures"]))

        # EXISTS CHECK
        exists = await service.exists(approval_id)
        assert exists, "Approval should exist"
        logger.info("approval_exists", exists=exists)

        # UPDATE (reject)
        rejected = await service.reject_approval(
            approval_id=approval_id,
            rejector_id="test-ciso",
            rejector_name="資安長測試",
            reason="Phase 6.1.1 自動化測試拒絕",
        )
        assert rejected["status"] == "rejected", f"Expected rejected, got {rejected['status']}"
        logger.info("approval_rejected",
                    status=rejected["status"],
                    rejector=rejected.get("rejector_name"))

        logger.info("TEST_2_APPROVAL_CRUD", status="PASSED")
        return True

    except Exception as e:
        logger.error("TEST_2_APPROVAL_CRUD", status="FAILED", error=str(e))
        import traceback
        traceback.print_exc()
        return False


async def test_signature_flow():
    """測試 3: 簽核流程 (含分散式鎖)"""
    logger.info("=" * 60)
    logger.info("TEST_3_SIGNATURE_FLOW", status="starting")

    from src.services.multi_sig_redis import get_multi_sig_redis_service

    service = get_multi_sig_redis_service()
    approval_id = str(uuid4())

    try:
        # 建立需要 2 人簽核的單子
        await service.create_approval(
            approval_id=approval_id,
            action="RESTART_SERVICE",
            description="測試簽核流程",
            risk_level="critical",
            required_signatures=2,
            namespace="awoooi",
        )
        logger.info("approval_created_for_signing", id=approval_id, required=2)

        # 第一人簽核
        state1 = await service.add_signature(
            approval_id=approval_id,
            signer_id="cto-001",
            signer_name="技術長",
            comment="同意執行",
            source="web",
        )
        logger.info("signature_1_added",
                    current=state1["current_signatures"],
                    required=state1["required_signatures"],
                    status=state1["status"])
        assert state1["status"] == "pending", "Should still be pending with 1/2 signatures"

        # 第二人簽核 (應該觸發 approved)
        state2 = await service.add_signature(
            approval_id=approval_id,
            signer_id="ceo-001",
            signer_name="執行長",
            comment="核准",
            source="telegram",
            telegram_user_id=123456789,
        )
        logger.info("signature_2_added",
                    current=state2["current_signatures"],
                    required=state2["required_signatures"],
                    status=state2["status"])
        assert state2["status"] == "approved", f"Should be approved, got {state2['status']}"

        logger.info("TEST_3_SIGNATURE_FLOW", status="PASSED")
        return True

    except Exception as e:
        logger.error("TEST_3_SIGNATURE_FLOW", status="FAILED", error=str(e))
        import traceback
        traceback.print_exc()
        return False


async def test_duplicate_signature_defense():
    """測試 4: 雙重簽核防禦"""
    logger.info("=" * 60)
    logger.info("TEST_4_DUPLICATE_SIGNATURE_DEFENSE", status="starting")

    from src.services.multi_sig_redis import get_multi_sig_redis_service

    service = get_multi_sig_redis_service()
    approval_id = str(uuid4())

    try:
        await service.create_approval(
            approval_id=approval_id,
            action="SCALE_DEPLOYMENT",
            description="雙重簽核防禦測試",
            risk_level="medium",
            required_signatures=3,
        )

        # 第一次簽核
        await service.add_signature(
            approval_id=approval_id,
            signer_id="same-user",
            signer_name="測試用戶",
        )
        logger.info("first_signature_success", signer="same-user")

        # 嘗試重複簽核 (應該被拒絕)
        try:
            await service.add_signature(
                approval_id=approval_id,
                signer_id="same-user",
                signer_name="測試用戶",
            )
            logger.error("duplicate_signature_allowed", status="SECURITY_BREACH")
            return False
        except RuntimeError as e:
            if "Already signed" in str(e):
                logger.info("duplicate_signature_blocked", error=str(e))
            else:
                raise

        logger.info("TEST_4_DUPLICATE_SIGNATURE_DEFENSE", status="PASSED")
        return True

    except Exception as e:
        logger.error("TEST_4_DUPLICATE_SIGNATURE_DEFENSE", status="FAILED", error=str(e))
        import traceback
        traceback.print_exc()
        return False


async def test_ttl_verification():
    """測試 5: TTL 驗證 (7 天 = 604800 秒)"""
    logger.info("=" * 60)
    logger.info("TEST_5_TTL_VERIFICATION", status="starting")

    from src.core.redis_client import get_redis
    from src.services.multi_sig_redis import (
        APPROVAL_TTL_SECONDS,
        get_multi_sig_redis_service,
    )

    service = get_multi_sig_redis_service()
    redis_client = get_redis()
    approval_id = str(uuid4())

    try:
        await service.create_approval(
            approval_id=approval_id,
            action="TTL_TEST",
            description="TTL 驗證測試",
            risk_level="low",
            required_signatures=1,
        )

        # 檢查 TTL
        key = f"approval:{approval_id}"
        ttl = await redis_client.ttl(key)

        logger.info("ttl_check",
                    key=key,
                    ttl_seconds=ttl,
                    expected_ttl=APPROVAL_TTL_SECONDS,
                    ttl_days=ttl / 86400 if ttl > 0 else 0)

        # TTL 應該接近 604800 秒 (允許 10 秒誤差)
        assert ttl > APPROVAL_TTL_SECONDS - 10, f"TTL too low: {ttl}"
        assert ttl <= APPROVAL_TTL_SECONDS, f"TTL too high: {ttl}"

        logger.info("TEST_5_TTL_VERIFICATION", status="PASSED")
        return True

    except Exception as e:
        logger.error("TEST_5_TTL_VERIFICATION", status="FAILED", error=str(e))
        import traceback
        traceback.print_exc()
        return False


async def test_concurrent_signatures():
    """測試 6: 併發簽核測試 (分散式鎖壓力測試)"""
    logger.info("=" * 60)
    logger.info("TEST_6_CONCURRENT_SIGNATURES", status="starting")

    from src.services.multi_sig_redis import get_multi_sig_redis_service

    service = get_multi_sig_redis_service()
    approval_id = str(uuid4())

    try:
        await service.create_approval(
            approval_id=approval_id,
            action="CONCURRENT_TEST",
            description="併發鎖測試",
            risk_level="high",
            required_signatures=5,
        )

        # 模擬 5 個不同用戶同時簽核
        async def sign(user_num: int):
            try:
                result = await service.add_signature(
                    approval_id=approval_id,
                    signer_id=f"user-{user_num}",
                    signer_name=f"用戶 {user_num}",
                    source="concurrent_test",
                )
                return ("success", user_num, result["current_signatures"])
            except Exception as e:
                return ("error", user_num, str(e))

        # 同時發起 5 個簽核請求
        tasks = [sign(i) for i in range(1, 6)]
        results = await asyncio.gather(*tasks)

        success_count = sum(1 for r in results if r[0] == "success")
        error_count = sum(1 for r in results if r[0] == "error")

        for status, user_num, detail in results:
            logger.info("concurrent_result",
                        user=user_num,
                        status=status,
                        detail=detail)

        logger.info("concurrent_summary",
                    success=success_count,
                    errors=error_count)

        # 驗證最終狀態
        final = await service.get_approval(approval_id)
        logger.info("final_state",
                    current_signatures=final["current_signatures"],
                    status=final["status"])

        # 所有 5 個簽核都應成功
        assert success_count == 5, f"Expected 5 successes, got {success_count}"
        assert final["status"] == "approved", f"Expected approved, got {final['status']}"

        logger.info("TEST_6_CONCURRENT_SIGNATURES", status="PASSED")
        return True

    except Exception as e:
        logger.error("TEST_6_CONCURRENT_SIGNATURES", status="FAILED", error=str(e))
        import traceback
        traceback.print_exc()
        return False


async def test_list_pending():
    """測試 7: 列出待簽核單"""
    logger.info("=" * 60)
    logger.info("TEST_7_LIST_PENDING", status="starting")

    from src.services.multi_sig_redis import get_multi_sig_redis_service

    service = get_multi_sig_redis_service()

    try:
        # 建立幾個待簽核單
        ids = []
        for i in range(3):
            approval_id = str(uuid4())
            await service.create_approval(
                approval_id=approval_id,
                action=f"LIST_TEST_{i}",
                description=f"列表測試 {i}",
                risk_level="low",
                required_signatures=1,
            )
            ids.append(approval_id)

        # 列出待簽核單
        pending = await service.list_pending(limit=100)
        logger.info("pending_list_count", count=len(pending))

        # 應該至少包含我們建立的 3 個
        found = sum(1 for p in pending if p["id"] in ids)
        logger.info("found_our_approvals", found=found, expected=3)

        assert found >= 3, f"Expected at least 3, found {found}"

        logger.info("TEST_7_LIST_PENDING", status="PASSED")
        return True

    except Exception as e:
        logger.error("TEST_7_LIST_PENDING", status="FAILED", error=str(e))
        import traceback
        traceback.print_exc()
        return False


async def main():
    """主測試入口"""
    logger.info("=" * 60)
    logger.info("PHASE_6_1_1_REDIS_MULTISIG_TEST", status="STARTING")
    logger.info("timestamp", time=datetime.now(UTC).isoformat())
    logger.info("=" * 60)

    results = {}

    # 測試 1: Redis 連線
    results["redis_connection"] = await test_redis_connection()

    if not results["redis_connection"]:
        logger.error("CRITICAL", message="Redis 連線失敗，終止測試")
        return

    # 測試 2-7
    results["approval_crud"] = await test_approval_crud()
    results["signature_flow"] = await test_signature_flow()
    results["duplicate_defense"] = await test_duplicate_signature_defense()
    results["ttl_verification"] = await test_ttl_verification()
    results["concurrent_signatures"] = await test_concurrent_signatures()
    results["list_pending"] = await test_list_pending()

    # 關閉連線池
    from src.core.redis_client import close_redis_pool
    await close_redis_pool()

    # 總結報告
    logger.info("=" * 60)
    logger.info("TEST_SUMMARY")

    passed = sum(1 for v in results.values() if v)
    failed = sum(1 for v in results.values() if not v)

    for test_name, passed_flag in results.items():
        status = "✅ PASSED" if passed_flag else "❌ FAILED"
        logger.info(f"  {test_name}: {status}")

    logger.info("-" * 60)
    logger.info(f"TOTAL: {passed} passed, {failed} failed")
    logger.info("=" * 60)

    if failed > 0:
        sys.exit(1)
    else:
        logger.info("ALL_TESTS_PASSED", message="Phase 6.1.1 Redis Multi-Sig 驗證完成")
        sys.exit(0)


if __name__ == "__main__":
    asyncio.run(main())
