"""
Comprehensive API Endpoint Tests for ClaudeTools Phase 5 Endpoints

This test suite validates all 12 Phase 5 API endpoints across 3 categories:

MSP Work Tracking (3 entities):
- Work Items API - /api/work-items
- Tasks API - /api/tasks
- Billable Time API - /api/billable-time

Infrastructure Management (6 entities):
- Sites API - /api/sites
- Infrastructure API - /api/infrastructure
- Services API - /api/services
- Networks API - /api/networks
- Firewall Rules API - /api/firewall-rules
- M365 Tenants API - /api/m365-tenants

Credentials Management (3 entities):
- Credentials API - /api/credentials (with encryption!)
- Credential Audit Logs API - /api/credential-audit-logs (read-only)
- Security Incidents API - /api/security-incidents

Tests include:
- CRUD operations for all entities
- Authentication (with JWT tokens)
- Pagination parameters
- Relationship queries (by-client, by-site, etc.)
- Special features (encryption for credentials, audit log creation)
- Error handling (404, 409, 422 responses)
"""

import sys
from datetime import date, timedelta
from uuid import uuid4

from fastapi.testclient import TestClient

# Import the FastAPI app and auth utilities
from api.main import app
from api.middleware.auth import create_access_token

# Create test client
client = TestClient(app)

# Test counters
tests_passed = 0
tests_failed = 0
test_results = []

# Track created entities for cleanup
created_entities = {
    "clients": [],
    "sites": [],
    "projects": [],
    "sessions": [],
    "work_items": [],
    "tasks": [],
    "billable_time": [],
    "infrastructure": [],
    "services": [],
    "networks": [],
    "firewall_rules": [],
    "m365_tenants": [],
    "credentials": [],
    "security_incidents": [],
}


def log_test(test_name: str, passed: bool, error_msg: str = ""):
    """Log test result and update counters."""
    global tests_passed, tests_failed
    if passed:
        tests_passed += 1
        status = "PASS"
        symbol = "[+]"
    else:
        tests_failed += 1
        status = "FAIL"
        symbol = "[-]"

    result = f"{symbol} {status}: {test_name}"
    if error_msg:
        result += f"\n  Error: {error_msg}"

    test_results.append((test_name, passed, error_msg))
    print(result)


def create_test_token():
    """Create a test JWT token for authentication."""
    token_data = {
        "sub": "test_user@claudetools.com",
        "scopes": ["msp:read", "msp:write", "msp:admin"]
    }
    return create_access_token(token_data, expires_delta=timedelta(hours=1))


def get_auth_headers():
    """Get authorization headers with test token."""
    token = create_test_token()
    return {"Authorization": f"Bearer {token}"}


# ============================================================================
# SECTION 1: MSP Work Tracking - Work Items API
# ============================================================================

print("\n" + "="*70)
print("SECTION 1: Work Items API Tests")
print("="*70 + "\n")

# First, create dependencies (client, project, session)
work_items_client_id = None
work_items_project_id = None
work_items_session_id = None
work_item_id = None


def test_create_work_items_dependencies():
    """Create client, project, and session for work items tests."""
    global work_items_client_id, work_items_project_id, work_items_session_id
    try:
        headers = get_auth_headers()

        # Create client
        client_data = {
            "name": f"WorkItems Test Client {uuid4().hex[:8]}",
            "type": "msp_client",
            "is_active": True
        }
        response = client.post("/api/clients", json=client_data, headers=headers)
        assert response.status_code == 201, f"Failed to create client: {response.text}"
        work_items_client_id = response.json()["id"]
        created_entities["clients"].append(work_items_client_id)

        # Create project
        project_data = {
            "name": f"WorkItems Test Project {uuid4().hex[:8]}",
            "client_id": work_items_client_id,
            "status": "active"
        }
        response = client.post("/api/projects", json=project_data, headers=headers)
        assert response.status_code == 201, f"Failed to create project: {response.text}"
        work_items_project_id = response.json()["id"]
        created_entities["projects"].append(work_items_project_id)

        # Create session
        session_data = {
            "session_title": f"WorkItems Test Session {uuid4().hex[:8]}",
            "session_date": str(date.today()),
            "client_id": work_items_client_id,
            "project_id": work_items_project_id,
            "status": "completed"
        }
        response = client.post("/api/sessions", json=session_data, headers=headers)
        assert response.status_code == 201, f"Failed to create session: {response.text}"
        work_items_session_id = response.json()["id"]
        created_entities["sessions"].append(work_items_session_id)

        log_test("Create work items dependencies (client, project, session)", True)
    except Exception as e:
        log_test("Create work items dependencies (client, project, session)", False, str(e))


def test_create_work_item():
    """Test creating a work item."""
    global work_item_id
    try:
        headers = get_auth_headers()
        work_item_data = {
            "session_id": work_items_session_id,
            "category": "infrastructure",
            "title": f"Test Work Item {uuid4().hex[:8]}",
            "description": "Testing work item creation",
            "status": "completed",
            "priority": "high",
            "is_billable": True,
            "estimated_minutes": 30,
            "actual_minutes": 25
        }
        response = client.post("/api/work-items", json=work_item_data, headers=headers)
        assert response.status_code == 201, f"Expected 201, got {response.status_code}. Response: {response.text}"
        data = response.json()
        assert "id" in data, "Response missing 'id' field"
        work_item_id = data["id"]
        created_entities["work_items"].append(work_item_id)
        print(f"  Created work item with ID: {work_item_id}")
        log_test("Create work item", True)
    except Exception as e:
        log_test("Create work item", False, str(e))


def test_list_work_items():
    """Test listing work items."""
    try:
        headers = get_auth_headers()
        response = client.get("/api/work-items?skip=0&limit=10", headers=headers)
        assert response.status_code == 200, f"Expected 200, got {response.status_code}"
        data = response.json()
        assert "total" in data, "Response missing 'total' field"
        assert "work_items" in data, "Response missing 'work_items' field"
        log_test("List work items", True)
    except Exception as e:
        log_test("List work items", False, str(e))


def test_get_work_item():
    """Test getting a specific work item."""
    try:
        if work_item_id is None:
            raise Exception("No work_item_id available")
        headers = get_auth_headers()
        response = client.get(f"/api/work-items/{work_item_id}", headers=headers)
        assert response.status_code == 200, f"Expected 200, got {response.status_code}"
        data = response.json()
        assert data["id"] == work_item_id, f"Expected ID {work_item_id}, got {data.get('id')}"
        log_test("Get work item by ID", True)
    except Exception as e:
        log_test("Get work item by ID", False, str(e))


def test_update_work_item():
    """Test updating a work item."""
    try:
        if work_item_id is None:
            raise Exception("No work_item_id available")
        headers = get_auth_headers()
        update_data = {
            "status": "completed",
            "actual_minutes": 30
        }
        response = client.put(f"/api/work-items/{work_item_id}", json=update_data, headers=headers)
        assert response.status_code == 200, f"Expected 200, got {response.status_code}"
        data = response.json()
        assert data["actual_minutes"] == 30, "Update not reflected"
        log_test("Update work item", True)
    except Exception as e:
        log_test("Update work item", False, str(e))


def test_get_work_items_by_client():
    """Test getting work items by client."""
    try:
        headers = get_auth_headers()
        response = client.get(f"/api/work-items/by-client/{work_items_client_id}?skip=0&limit=10", headers=headers)
        assert response.status_code == 200, f"Expected 200, got {response.status_code}"
        data = response.json()
        assert "work_items" in data, "Response missing 'work_items' field"
        log_test("Get work items by client", True)
    except Exception as e:
        log_test("Get work items by client", False, str(e))


# ============================================================================
# SECTION 2: MSP Work Tracking - Tasks API
# ============================================================================

print("\n" + "="*70)
print("SECTION 2: Tasks API Tests")
print("="*70 + "\n")

task_id = None


def test_create_task():
    """Test creating a task."""
    global task_id
    try:
        headers = get_auth_headers()
        task_data = {
            "client_id": work_items_client_id,
            "title": f"Test Task {uuid4().hex[:8]}",
            "description": "Testing task creation",
            "status": "pending",
            "task_order": 1
        }
        response = client.post("/api/tasks", json=task_data, headers=headers)
        assert response.status_code == 201, f"Expected 201, got {response.status_code}. Response: {response.text}"
        data = response.json()
        assert "id" in data, "Response missing 'id' field"
        task_id = data["id"]
        created_entities["tasks"].append(task_id)
        print(f"  Created task with ID: {task_id}")
        log_test("Create task", True)
    except Exception as e:
        log_test("Create task", False, str(e))


def test_list_tasks():
    """Test listing tasks."""
    try:
        headers = get_auth_headers()
        response = client.get("/api/tasks?skip=0&limit=10", headers=headers)
        assert response.status_code == 200, f"Expected 200, got {response.status_code}"
        data = response.json()
        assert "total" in data, "Response missing 'total' field"
        assert "tasks" in data, "Response missing 'tasks' field"
        log_test("List tasks", True)
    except Exception as e:
        log_test("List tasks", False, str(e))


def test_get_task():
    """Test getting a specific task."""
    try:
        if task_id is None:
            raise Exception("No task_id available")
        headers = get_auth_headers()
        response = client.get(f"/api/tasks/{task_id}", headers=headers)
        assert response.status_code == 200, f"Expected 200, got {response.status_code}"
        data = response.json()
        assert data["id"] == task_id, f"Expected ID {task_id}, got {data.get('id')}"
        log_test("Get task by ID", True)
    except Exception as e:
        log_test("Get task by ID", False, str(e))


def test_update_task():
    """Test updating a task."""
    try:
        if task_id is None:
            raise Exception("No task_id available")
        headers = get_auth_headers()
        update_data = {
            "status": "in_progress",
            "priority": "high"
        }
        response = client.put(f"/api/tasks/{task_id}", json=update_data, headers=headers)
        assert response.status_code == 200, f"Expected 200, got {response.status_code}"
        data = response.json()
        assert data["status"] == "in_progress", "Update not reflected"
        log_test("Update task", True)
    except Exception as e:
        log_test("Update task", False, str(e))


def test_get_tasks_filtering():
    """Test getting tasks with status filtering."""
    try:
        headers = get_auth_headers()
        response = client.get(f"/api/tasks?status_filter=pending&skip=0&limit=10", headers=headers)
        assert response.status_code == 200, f"Expected 200, got {response.status_code}"
        data = response.json()
        assert "tasks" in data, "Response missing 'tasks' field"
        log_test("Get tasks with status filtering", True)
    except Exception as e:
        log_test("Get tasks with status filtering", False, str(e))


# ============================================================================
# SECTION 3: MSP Work Tracking - Billable Time API
# ============================================================================

print("\n" + "="*70)
print("SECTION 3: Billable Time API Tests")
print("="*70 + "\n")

billable_time_id = None


def test_create_billable_time():
    """Test creating a billable time entry."""
    global billable_time_id
    try:
        headers = get_auth_headers()
        from datetime import datetime
        billable_time_data = {
            "client_id": work_items_client_id,
            "session_id": work_items_session_id,
            "work_item_id": work_item_id,
            "description": "Testing billable time entry",
            "start_time": datetime.now().isoformat(),
            "duration_minutes": 60,
            "hourly_rate": 150.00,
            "total_amount": 150.00,
            "category": "consulting",
            "is_billable": True
        }
        response = client.post("/api/billable-time", json=billable_time_data, headers=headers)
        assert response.status_code == 201, f"Expected 201, got {response.status_code}. Response: {response.text}"
        data = response.json()
        assert "id" in data, "Response missing 'id' field"
        billable_time_id = data["id"]
        created_entities["billable_time"].append(billable_time_id)
        print(f"  Created billable time with ID: {billable_time_id}")
        log_test("Create billable time", True)
    except Exception as e:
        log_test("Create billable time", False, str(e))


def test_list_billable_time():
    """Test listing billable time entries."""
    try:
        headers = get_auth_headers()
        response = client.get("/api/billable-time?skip=0&limit=10", headers=headers)
        assert response.status_code == 200, f"Expected 200, got {response.status_code}"
        data = response.json()
        assert "total" in data, "Response missing 'total' field"
        assert "billable_time" in data, "Response missing 'billable_time' field"
        log_test("List billable time", True)
    except Exception as e:
        log_test("List billable time", False, str(e))


def test_get_billable_time():
    """Test getting a specific billable time entry."""
    try:
        if billable_time_id is None:
            raise Exception("No billable_time_id available")
        headers = get_auth_headers()
        response = client.get(f"/api/billable-time/{billable_time_id}", headers=headers)
        assert response.status_code == 200, f"Expected 200, got {response.status_code}"
        data = response.json()
        assert data["id"] == billable_time_id, f"Expected ID {billable_time_id}, got {data.get('id')}"
        log_test("Get billable time by ID", True)
    except Exception as e:
        log_test("Get billable time by ID", False, str(e))


def test_update_billable_time():
    """Test updating a billable time entry."""
    try:
        if billable_time_id is None:
            raise Exception("No billable_time_id available")
        headers = get_auth_headers()
        update_data = {
            "duration_minutes": 90,
            "hourly_rate": 175.00,
            "total_amount": 262.50
        }
        response = client.put(f"/api/billable-time/{billable_time_id}", json=update_data, headers=headers)
        assert response.status_code == 200, f"Expected 200, got {response.status_code}"
        data = response.json()
        assert data["duration_minutes"] == 90, "Update not reflected"
        log_test("Update billable time", True)
    except Exception as e:
        log_test("Update billable time", False, str(e))


def test_get_billable_time_by_session():
    """Test getting billable time by session."""
    try:
        headers = get_auth_headers()
        response = client.get(f"/api/billable-time/by-session/{work_items_session_id}?skip=0&limit=10", headers=headers)
        assert response.status_code == 200, f"Expected 200, got {response.status_code}"
        data = response.json()
        assert "billable_time" in data, "Response missing 'billable_time' field"
        log_test("Get billable time by session", True)
    except Exception as e:
        log_test("Get billable time by session", False, str(e))


# ============================================================================
# SECTION 4: Infrastructure Management - Sites API
# ============================================================================

print("\n" + "="*70)
print("SECTION 4: Sites API Tests")
print("="*70 + "\n")

site_id = None


def test_create_site():
    """Test creating a site."""
    global site_id
    try:
        headers = get_auth_headers()
        site_data = {
            "client_id": work_items_client_id,
            "name": f"Test Site {uuid4().hex[:8]}",
            "network_subnet": "172.16.1.0/24",
            "vpn_required": True,
            "gateway_ip": "172.16.1.1"
        }
        response = client.post("/api/sites", json=site_data, headers=headers)
        assert response.status_code == 201, f"Expected 201, got {response.status_code}. Response: {response.text}"
        data = response.json()
        assert "id" in data, "Response missing 'id' field"
        site_id = data["id"]
        created_entities["sites"].append(site_id)
        print(f"  Created site with ID: {site_id}")
        log_test("Create site", True)
    except Exception as e:
        log_test("Create site", False, str(e))


def test_list_sites():
    """Test listing sites."""
    try:
        headers = get_auth_headers()
        response = client.get("/api/sites?skip=0&limit=10", headers=headers)
        assert response.status_code == 200, f"Expected 200, got {response.status_code}"
        data = response.json()
        assert "total" in data, "Response missing 'total' field"
        assert "sites" in data, "Response missing 'sites' field"
        log_test("List sites", True)
    except Exception as e:
        log_test("List sites", False, str(e))


def test_get_site():
    """Test getting a specific site."""
    try:
        if site_id is None:
            raise Exception("No site_id available")
        headers = get_auth_headers()
        response = client.get(f"/api/sites/{site_id}", headers=headers)
        assert response.status_code == 200, f"Expected 200, got {response.status_code}"
        data = response.json()
        assert data["id"] == site_id, f"Expected ID {site_id}, got {data.get('id')}"
        log_test("Get site by ID", True)
    except Exception as e:
        log_test("Get site by ID", False, str(e))


def test_update_site():
    """Test updating a site."""
    try:
        if site_id is None:
            raise Exception("No site_id available")
        headers = get_auth_headers()
        update_data = {
            "vpn_required": False,
            "notes": "VPN disabled"
        }
        response = client.put(f"/api/sites/{site_id}", json=update_data, headers=headers)
        assert response.status_code == 200, f"Expected 200, got {response.status_code}"
        data = response.json()
        assert data["vpn_required"] == False, "Update not reflected"
        log_test("Update site", True)
    except Exception as e:
        log_test("Update site", False, str(e))


def test_get_sites_by_client():
    """Test getting sites by client."""
    try:
        headers = get_auth_headers()
        response = client.get(f"/api/sites/by-client/{work_items_client_id}?skip=0&limit=10", headers=headers)
        assert response.status_code == 200, f"Expected 200, got {response.status_code}"
        data = response.json()
        assert "sites" in data, "Response missing 'sites' field"
        log_test("Get sites by client", True)
    except Exception as e:
        log_test("Get sites by client", False, str(e))


# ============================================================================
# SECTION 5: Infrastructure Management - Infrastructure API
# ============================================================================

print("\n" + "="*70)
print("SECTION 5: Infrastructure API Tests")
print("="*70 + "\n")

infrastructure_id = None


def test_create_infrastructure():
    """Test creating an infrastructure component."""
    global infrastructure_id
    try:
        headers = get_auth_headers()
        infra_data = {
            "site_id": site_id,
            "asset_type": "physical_server",
            "hostname": f"test-server-{uuid4().hex[:8]}",
            "ip_address": "172.16.1.100",
            "status": "active"
        }
        response = client.post("/api/infrastructure", json=infra_data, headers=headers)
        assert response.status_code == 201, f"Expected 201, got {response.status_code}. Response: {response.text}"
        data = response.json()
        assert "id" in data, "Response missing 'id' field"
        infrastructure_id = data["id"]
        created_entities["infrastructure"].append(infrastructure_id)
        print(f"  Created infrastructure with ID: {infrastructure_id}")
        log_test("Create infrastructure", True)
    except Exception as e:
        log_test("Create infrastructure", False, str(e))


def test_list_infrastructure():
    """Test listing infrastructure components."""
    try:
        headers = get_auth_headers()
        response = client.get("/api/infrastructure?skip=0&limit=10", headers=headers)
        assert response.status_code == 200, f"Expected 200, got {response.status_code}"
        data = response.json()
        assert "total" in data, "Response missing 'total' field"
        assert "infrastructure" in data, "Response missing 'infrastructure' field"
        log_test("List infrastructure", True)
    except Exception as e:
        log_test("List infrastructure", False, str(e))


def test_get_infrastructure():
    """Test getting a specific infrastructure component."""
    try:
        if infrastructure_id is None:
            raise Exception("No infrastructure_id available")
        headers = get_auth_headers()
        response = client.get(f"/api/infrastructure/{infrastructure_id}", headers=headers)
        assert response.status_code == 200, f"Expected 200, got {response.status_code}"
        data = response.json()
        assert data["id"] == infrastructure_id, f"Expected ID {infrastructure_id}, got {data.get('id')}"
        log_test("Get infrastructure by ID", True)
    except Exception as e:
        log_test("Get infrastructure by ID", False, str(e))


def test_update_infrastructure():
    """Test updating an infrastructure component."""
    try:
        if infrastructure_id is None:
            raise Exception("No infrastructure_id available")
        headers = get_auth_headers()
        update_data = {
            "os": "Ubuntu 24.04",
            "notes": "OS updated"
        }
        response = client.put(f"/api/infrastructure/{infrastructure_id}", json=update_data, headers=headers)
        assert response.status_code == 200, f"Expected 200, got {response.status_code}"
        data = response.json()
        assert data["os"] == "Ubuntu 24.04", "Update not reflected"
        log_test("Update infrastructure", True)
    except Exception as e:
        log_test("Update infrastructure", False, str(e))


def test_get_infrastructure_by_site():
    """Test getting infrastructure by site."""
    try:
        headers = get_auth_headers()
        response = client.get(f"/api/infrastructure/by-site/{site_id}?skip=0&limit=10", headers=headers)
        assert response.status_code == 200, f"Expected 200, got {response.status_code}"
        data = response.json()
        assert "infrastructure" in data, "Response missing 'infrastructure' field"
        log_test("Get infrastructure by site", True)
    except Exception as e:
        log_test("Get infrastructure by site", False, str(e))


# ============================================================================
# SECTION 6: Infrastructure Management - Services API
# ============================================================================

print("\n" + "="*70)
print("SECTION 6: Services API Tests")
print("="*70 + "\n")

service_id = None


def test_create_service():
    """Test creating a service."""
    global service_id
    try:
        headers = get_auth_headers()
        service_data = {
            "infrastructure_id": infrastructure_id,
            "service_name": f"Test Service {uuid4().hex[:8]}",
            "service_type": "web_server",
            "port": 443,
            "protocol": "https",
            "status": "running"
        }
        response = client.post("/api/services", json=service_data, headers=headers)
        assert response.status_code == 201, f"Expected 201, got {response.status_code}. Response: {response.text}"
        data = response.json()
        assert "id" in data, "Response missing 'id' field"
        service_id = data["id"]
        created_entities["services"].append(service_id)
        print(f"  Created service with ID: {service_id}")
        log_test("Create service", True)
    except Exception as e:
        log_test("Create service", False, str(e))


def test_list_services():
    """Test listing services."""
    try:
        headers = get_auth_headers()
        response = client.get("/api/services?skip=0&limit=10", headers=headers)
        assert response.status_code == 200, f"Expected 200, got {response.status_code}"
        data = response.json()
        assert "total" in data, "Response missing 'total' field"
        assert "services" in data, "Response missing 'services' field"
        log_test("List services", True)
    except Exception as e:
        log_test("List services", False, str(e))


def test_get_service():
    """Test getting a specific service."""
    try:
        if service_id is None:
            raise Exception("No service_id available")
        headers = get_auth_headers()
        response = client.get(f"/api/services/{service_id}", headers=headers)
        assert response.status_code == 200, f"Expected 200, got {response.status_code}"
        data = response.json()
        assert data["id"] == service_id, f"Expected ID {service_id}, got {data.get('id')}"
        log_test("Get service by ID", True)
    except Exception as e:
        log_test("Get service by ID", False, str(e))


def test_update_service():
    """Test updating a service."""
    try:
        if service_id is None:
            raise Exception("No service_id available")
        headers = get_auth_headers()
        update_data = {
            "status": "stopped",
            "notes": "Service stopped for maintenance"
        }
        response = client.put(f"/api/services/{service_id}", json=update_data, headers=headers)
        assert response.status_code == 200, f"Expected 200, got {response.status_code}"
        data = response.json()
        assert data["status"] == "stopped", "Update not reflected"
        log_test("Update service", True)
    except Exception as e:
        log_test("Update service", False, str(e))


def test_get_services_by_client():
    """Test getting services by client."""
    try:
        headers = get_auth_headers()
        response = client.get(f"/api/services/by-client/{work_items_client_id}?skip=0&limit=10", headers=headers)
        assert response.status_code == 200, f"Expected 200, got {response.status_code}"
        data = response.json()
        assert "services" in data, "Response missing 'services' field"
        log_test("Get services by client", True)
    except Exception as e:
        log_test("Get services by client", False, str(e))


# ============================================================================
# SECTION 7: Infrastructure Management - Networks API
# ============================================================================

print("\n" + "="*70)
print("SECTION 7: Networks API Tests")
print("="*70 + "\n")

network_id = None


def test_create_network():
    """Test creating a network."""
    global network_id
    try:
        headers = get_auth_headers()
        network_data = {
            "site_id": site_id,
            "network_name": f"Test Network {uuid4().hex[:8]}",
            "cidr": "10.0.1.0/24",
            "vlan_id": 100,
            "network_type": "lan"
        }
        response = client.post("/api/networks", json=network_data, headers=headers)
        assert response.status_code == 201, f"Expected 201, got {response.status_code}. Response: {response.text}"
        data = response.json()
        assert "id" in data, "Response missing 'id' field"
        network_id = data["id"]
        created_entities["networks"].append(network_id)
        print(f"  Created network with ID: {network_id}")
        log_test("Create network", True)
    except Exception as e:
        log_test("Create network", False, str(e))


def test_list_networks():
    """Test listing networks."""
    try:
        headers = get_auth_headers()
        response = client.get("/api/networks?skip=0&limit=10", headers=headers)
        assert response.status_code == 200, f"Expected 200, got {response.status_code}"
        data = response.json()
        assert "total" in data, "Response missing 'total' field"
        assert "networks" in data, "Response missing 'networks' field"
        log_test("List networks", True)
    except Exception as e:
        log_test("List networks", False, str(e))


def test_get_network():
    """Test getting a specific network."""
    try:
        if network_id is None:
            raise Exception("No network_id available")
        headers = get_auth_headers()
        response = client.get(f"/api/networks/{network_id}", headers=headers)
        assert response.status_code == 200, f"Expected 200, got {response.status_code}"
        data = response.json()
        assert data["id"] == network_id, f"Expected ID {network_id}, got {data.get('id')}"
        log_test("Get network by ID", True)
    except Exception as e:
        log_test("Get network by ID", False, str(e))


def test_update_network():
    """Test updating a network."""
    try:
        if network_id is None:
            raise Exception("No network_id available")
        headers = get_auth_headers()
        update_data = {
            "vlan_id": 200,
            "notes": "VLAN updated"
        }
        response = client.put(f"/api/networks/{network_id}", json=update_data, headers=headers)
        assert response.status_code == 200, f"Expected 200, got {response.status_code}"
        data = response.json()
        assert data["vlan_id"] == 200, "Update not reflected"
        log_test("Update network", True)
    except Exception as e:
        log_test("Update network", False, str(e))


def test_get_networks_by_site():
    """Test getting networks by site."""
    try:
        headers = get_auth_headers()
        response = client.get(f"/api/networks/by-site/{site_id}?skip=0&limit=10", headers=headers)
        assert response.status_code == 200, f"Expected 200, got {response.status_code}"
        data = response.json()
        assert "networks" in data, "Response missing 'networks' field"
        log_test("Get networks by site", True)
    except Exception as e:
        log_test("Get networks by site", False, str(e))


# ============================================================================
# SECTION 8: Infrastructure Management - Firewall Rules API
# ============================================================================

print("\n" + "="*70)
print("SECTION 8: Firewall Rules API Tests")
print("="*70 + "\n")

firewall_rule_id = None


def test_create_firewall_rule():
    """Test creating a firewall rule."""
    global firewall_rule_id
    try:
        headers = get_auth_headers()
        firewall_data = {
            "infrastructure_id": infrastructure_id,
            "rule_name": f"Test Rule {uuid4().hex[:8]}",
            "source": "0.0.0.0/0",
            "destination": "172.16.1.100",
            "port": 443,
            "protocol": "tcp",
            "action": "allow",
            "priority": 100
        }
        response = client.post("/api/firewall-rules", json=firewall_data, headers=headers)
        assert response.status_code == 201, f"Expected 201, got {response.status_code}. Response: {response.text}"
        data = response.json()
        assert "id" in data, "Response missing 'id' field"
        firewall_rule_id = data["id"]
        created_entities["firewall_rules"].append(firewall_rule_id)
        print(f"  Created firewall rule with ID: {firewall_rule_id}")
        log_test("Create firewall rule", True)
    except Exception as e:
        log_test("Create firewall rule", False, str(e))


def test_list_firewall_rules():
    """Test listing firewall rules."""
    try:
        headers = get_auth_headers()
        response = client.get("/api/firewall-rules?skip=0&limit=10", headers=headers)
        assert response.status_code == 200, f"Expected 200, got {response.status_code}"
        data = response.json()
        assert "total" in data, "Response missing 'total' field"
        assert "firewall_rules" in data, "Response missing 'firewall_rules' field"
        log_test("List firewall rules", True)
    except Exception as e:
        log_test("List firewall rules", False, str(e))


def test_get_firewall_rule():
    """Test getting a specific firewall rule."""
    try:
        if firewall_rule_id is None:
            raise Exception("No firewall_rule_id available")
        headers = get_auth_headers()
        response = client.get(f"/api/firewall-rules/{firewall_rule_id}", headers=headers)
        assert response.status_code == 200, f"Expected 200, got {response.status_code}"
        data = response.json()
        assert data["id"] == firewall_rule_id, f"Expected ID {firewall_rule_id}, got {data.get('id')}"
        log_test("Get firewall rule by ID", True)
    except Exception as e:
        log_test("Get firewall rule by ID", False, str(e))


def test_update_firewall_rule():
    """Test updating a firewall rule."""
    try:
        if firewall_rule_id is None:
            raise Exception("No firewall_rule_id available")
        headers = get_auth_headers()
        update_data = {
            "action": "deny",
            "notes": "Rule changed to deny"
        }
        response = client.put(f"/api/firewall-rules/{firewall_rule_id}", json=update_data, headers=headers)
        assert response.status_code == 200, f"Expected 200, got {response.status_code}"
        data = response.json()
        assert data["action"] == "deny", "Update not reflected"
        log_test("Update firewall rule", True)
    except Exception as e:
        log_test("Update firewall rule", False, str(e))


def test_get_firewall_rules_by_infrastructure():
    """Test getting firewall rules by infrastructure."""
    try:
        headers = get_auth_headers()
        response = client.get(f"/api/firewall-rules/by-infrastructure/{infrastructure_id}?skip=0&limit=10", headers=headers)
        assert response.status_code == 200, f"Expected 200, got {response.status_code}"
        data = response.json()
        assert "firewall_rules" in data, "Response missing 'firewall_rules' field"
        log_test("Get firewall rules by infrastructure", True)
    except Exception as e:
        log_test("Get firewall rules by infrastructure", False, str(e))


# ============================================================================
# SECTION 9: Infrastructure Management - M365 Tenants API
# ============================================================================

print("\n" + "="*70)
print("SECTION 9: M365 Tenants API Tests")
print("="*70 + "\n")

m365_tenant_id = None


def test_create_m365_tenant():
    """Test creating an M365 tenant."""
    global m365_tenant_id
    try:
        headers = get_auth_headers()
        m365_data = {
            "client_id": work_items_client_id,
            "tenant_name": f"Test Tenant {uuid4().hex[:8]}",
            "tenant_id": str(uuid4()),
            "primary_domain": f"test{uuid4().hex[:8]}.onmicrosoft.com",
            "admin_email": "admin@test.com"
        }
        response = client.post("/api/m365-tenants", json=m365_data, headers=headers)
        assert response.status_code == 201, f"Expected 201, got {response.status_code}. Response: {response.text}"
        data = response.json()
        assert "id" in data, "Response missing 'id' field"
        m365_tenant_id = data["id"]
        created_entities["m365_tenants"].append(m365_tenant_id)
        print(f"  Created M365 tenant with ID: {m365_tenant_id}")
        log_test("Create M365 tenant", True)
    except Exception as e:
        log_test("Create M365 tenant", False, str(e))


def test_list_m365_tenants():
    """Test listing M365 tenants."""
    try:
        headers = get_auth_headers()
        response = client.get("/api/m365-tenants?skip=0&limit=10", headers=headers)
        assert response.status_code == 200, f"Expected 200, got {response.status_code}"
        data = response.json()
        assert "total" in data, "Response missing 'total' field"
        assert "m365_tenants" in data, "Response missing 'm365_tenants' field"
        log_test("List M365 tenants", True)
    except Exception as e:
        log_test("List M365 tenants", False, str(e))


def test_get_m365_tenant():
    """Test getting a specific M365 tenant."""
    try:
        if m365_tenant_id is None:
            raise Exception("No m365_tenant_id available")
        headers = get_auth_headers()
        response = client.get(f"/api/m365-tenants/{m365_tenant_id}", headers=headers)
        assert response.status_code == 200, f"Expected 200, got {response.status_code}"
        data = response.json()
        assert data["id"] == m365_tenant_id, f"Expected ID {m365_tenant_id}, got {data.get('id')}"
        log_test("Get M365 tenant by ID", True)
    except Exception as e:
        log_test("Get M365 tenant by ID", False, str(e))


def test_update_m365_tenant():
    """Test updating an M365 tenant."""
    try:
        if m365_tenant_id is None:
            raise Exception("No m365_tenant_id available")
        headers = get_auth_headers()
        update_data = {
            "admin_email": "newadmin@test.com",
            "notes": "Admin email updated"
        }
        response = client.put(f"/api/m365-tenants/{m365_tenant_id}", json=update_data, headers=headers)
        assert response.status_code == 200, f"Expected 200, got {response.status_code}"
        data = response.json()
        assert data["admin_email"] == "newadmin@test.com", "Update not reflected"
        log_test("Update M365 tenant", True)
    except Exception as e:
        log_test("Update M365 tenant", False, str(e))


def test_get_m365_tenants_by_client():
    """Test getting M365 tenants by client."""
    try:
        headers = get_auth_headers()
        response = client.get(f"/api/m365-tenants/by-client/{work_items_client_id}?skip=0&limit=10", headers=headers)
        assert response.status_code == 200, f"Expected 200, got {response.status_code}"
        data = response.json()
        assert "m365_tenants" in data, "Response missing 'm365_tenants' field"
        log_test("Get M365 tenants by client", True)
    except Exception as e:
        log_test("Get M365 tenants by client", False, str(e))


# ============================================================================
# SECTION 10: Credentials Management - Credentials API (with Encryption!)
# ============================================================================

print("\n" + "="*70)
print("SECTION 10: Credentials API Tests (with Encryption)")
print("="*70 + "\n")

credential_id = None


def test_create_credential_password():
    """Test creating a password credential with encryption."""
    global credential_id
    try:
        headers = get_auth_headers()
        credential_data = {
            "client_id": work_items_client_id,
            "service_id": service_id,
            "credential_type": "password",
            "service_name": f"Test Service Cred {uuid4().hex[:8]}",
            "username": "testuser",
            "password": "SuperSecretPassword123!",
            "requires_vpn": False,
            "requires_2fa": True,
            "is_active": True
        }
        response = client.post("/api/credentials", json=credential_data, headers=headers)
        assert response.status_code == 201, f"Expected 201, got {response.status_code}. Response: {response.text}"
        data = response.json()
        assert "id" in data, "Response missing 'id' field"
        credential_id = data["id"]
        created_entities["credentials"].append(credential_id)

        # Verify password is decrypted in response
        assert data["password"] == "SuperSecretPassword123!", "Password not decrypted in response"
        print(f"  Created credential with ID: {credential_id}")
        print(f"  Password encrypted and decrypted successfully: {data['password']}")
        log_test("Create credential with password encryption", True)
    except Exception as e:
        log_test("Create credential with password encryption", False, str(e))


def test_create_credential_api_key():
    """Test creating an API key credential with encryption."""
    try:
        headers = get_auth_headers()
        credential_data = {
            "client_id": work_items_client_id,
            "credential_type": "api_key",
            "service_name": f"Test API Key {uuid4().hex[:8]}",
            "api_key": "sk-test-1234567890abcdef",
            "is_active": True
        }
        response = client.post("/api/credentials", json=credential_data, headers=headers)
        assert response.status_code == 201, f"Expected 201, got {response.status_code}. Response: {response.text}"
        data = response.json()
        assert "id" in data, "Response missing 'id' field"
        created_entities["credentials"].append(data["id"])

        # Verify API key is decrypted in response
        assert data["api_key"] == "sk-test-1234567890abcdef", "API key not decrypted in response"
        print(f"  API key encrypted and decrypted successfully")
        log_test("Create credential with API key encryption", True)
    except Exception as e:
        log_test("Create credential with API key encryption", False, str(e))


def test_create_credential_oauth():
    """Test creating an OAuth credential with encryption."""
    try:
        headers = get_auth_headers()
        credential_data = {
            "client_id": work_items_client_id,
            "credential_type": "oauth",
            "service_name": f"Test OAuth {uuid4().hex[:8]}",
            "client_id_oauth": "oauth-client-id-123",
            "client_secret": "oauth-secret-xyz789",
            "tenant_id_oauth": "tenant-abc-456",
            "is_active": True
        }
        response = client.post("/api/credentials", json=credential_data, headers=headers)
        assert response.status_code == 201, f"Expected 201, got {response.status_code}. Response: {response.text}"
        data = response.json()
        assert "id" in data, "Response missing 'id' field"
        created_entities["credentials"].append(data["id"])

        # Verify client secret is decrypted in response
        assert data["client_secret"] == "oauth-secret-xyz789", "Client secret not decrypted in response"
        print(f"  OAuth client secret encrypted and decrypted successfully")
        log_test("Create credential with OAuth encryption", True)
    except Exception as e:
        log_test("Create credential with OAuth encryption", False, str(e))


def test_list_credentials():
    """Test listing credentials."""
    try:
        headers = get_auth_headers()
        response = client.get("/api/credentials?skip=0&limit=10", headers=headers)
        assert response.status_code == 200, f"Expected 200, got {response.status_code}"
        data = response.json()
        assert "total" in data, "Response missing 'total' field"
        assert "credentials" in data, "Response missing 'credentials' field"
        log_test("List credentials", True)
    except Exception as e:
        log_test("List credentials", False, str(e))


def test_get_credential():
    """Test getting a specific credential (should create audit log)."""
    try:
        if credential_id is None:
            raise Exception("No credential_id available")
        headers = get_auth_headers()
        response = client.get(f"/api/credentials/{credential_id}", headers=headers)
        assert response.status_code == 200, f"Expected 200, got {response.status_code}"
        data = response.json()
        assert data["id"] == credential_id, f"Expected ID {credential_id}, got {data.get('id')}"

        # Verify password is still decrypted
        assert data["password"] is not None, "Password not present in response"
        print(f"  Credential retrieved and audit log created")
        log_test("Get credential by ID (creates audit log)", True)
    except Exception as e:
        log_test("Get credential by ID (creates audit log)", False, str(e))


def test_update_credential():
    """Test updating a credential."""
    try:
        if credential_id is None:
            raise Exception("No credential_id available")
        headers = get_auth_headers()
        update_data = {
            "password": "NewSuperSecretPassword456!",
            "requires_2fa": False
        }
        response = client.put(f"/api/credentials/{credential_id}", json=update_data, headers=headers)
        assert response.status_code == 200, f"Expected 200, got {response.status_code}"
        data = response.json()

        # Verify new password is decrypted in response
        assert data["password"] == "NewSuperSecretPassword456!", "Password update not reflected"
        assert data["requires_2fa"] == False, "Update not reflected"
        print(f"  Password re-encrypted successfully")
        log_test("Update credential (re-encrypts password)", True)
    except Exception as e:
        log_test("Update credential (re-encrypts password)", False, str(e))


def test_get_credentials_by_client():
    """Test getting credentials by client."""
    try:
        headers = get_auth_headers()
        response = client.get(f"/api/credentials/by-client/{work_items_client_id}?skip=0&limit=10", headers=headers)
        assert response.status_code == 200, f"Expected 200, got {response.status_code}"
        data = response.json()
        assert "credentials" in data, "Response missing 'credentials' field"
        log_test("Get credentials by client", True)
    except Exception as e:
        log_test("Get credentials by client", False, str(e))


# ============================================================================
# SECTION 11: Credentials Management - Credential Audit Logs API (Read-Only)
# ============================================================================

print("\n" + "="*70)
print("SECTION 11: Credential Audit Logs API Tests (Read-Only)")
print("="*70 + "\n")


def test_list_credential_audit_logs():
    """Test listing credential audit logs."""
    try:
        headers = get_auth_headers()
        response = client.get("/api/credential-audit-logs?skip=0&limit=10", headers=headers)
        assert response.status_code == 200, f"Expected 200, got {response.status_code}"
        data = response.json()
        assert "total" in data, "Response missing 'total' field"
        assert "logs" in data, "Response missing 'logs' field"

        # Should have at least some audit logs from credential operations
        assert data["total"] > 0, "No audit logs found (should have been created by credential operations)"
        print(f"  Found {data['total']} audit log entries")
        log_test("List credential audit logs", True)
    except Exception as e:
        log_test("List credential audit logs", False, str(e))


def test_get_credential_audit_logs_by_credential():
    """Test getting audit logs for a specific credential."""
    try:
        if credential_id is None:
            raise Exception("No credential_id available")
        headers = get_auth_headers()
        response = client.get(f"/api/credential-audit-logs/by-credential/{credential_id}?skip=0&limit=10", headers=headers)
        assert response.status_code == 200, f"Expected 200, got {response.status_code}"
        data = response.json()
        assert "logs" in data, "Response missing 'logs' field"

        # Should have audit logs for CREATE, VIEW, and UPDATE actions
        assert data["total"] >= 3, f"Expected at least 3 audit logs (create, view, update), got {data['total']}"
        print(f"  Found {data['total']} audit logs for credential")
        log_test("Get audit logs by credential", True)
    except Exception as e:
        log_test("Get audit logs by credential", False, str(e))


def test_get_credential_audit_logs_by_user():
    """Test getting audit logs by user."""
    try:
        headers = get_auth_headers()
        user_id = "test_user@claudetools.com"
        response = client.get(f"/api/credential-audit-logs/by-user/{user_id}?skip=0&limit=10", headers=headers)
        assert response.status_code == 200, f"Expected 200, got {response.status_code}"
        data = response.json()
        assert "logs" in data, "Response missing 'logs' field"
        print(f"  Found {data['total']} audit logs for user")
        log_test("Get audit logs by user", True)
    except Exception as e:
        log_test("Get audit logs by user", False, str(e))


# ============================================================================
# SECTION 12: Credentials Management - Security Incidents API
# ============================================================================

print("\n" + "="*70)
print("SECTION 12: Security Incidents API Tests")
print("="*70 + "\n")

security_incident_id = None


def test_create_security_incident():
    """Test creating a security incident."""
    global security_incident_id
    try:
        headers = get_auth_headers()
        from datetime import datetime
        incident_data = {
            "client_id": work_items_client_id,
            "incident_type": "unauthorized_access",
            "severity": "high",
            "description": "Testing security incident creation",
            "incident_date": datetime.now().isoformat(),
            "status": "investigating"
        }
        response = client.post("/api/security-incidents", json=incident_data, headers=headers)
        assert response.status_code == 201, f"Expected 201, got {response.status_code}. Response: {response.text}"
        data = response.json()
        assert "id" in data, "Response missing 'id' field"
        security_incident_id = data["id"]
        created_entities["security_incidents"].append(security_incident_id)
        print(f"  Created security incident with ID: {security_incident_id}")
        log_test("Create security incident", True)
    except Exception as e:
        log_test("Create security incident", False, str(e))


def test_list_security_incidents():
    """Test listing security incidents."""
    try:
        headers = get_auth_headers()
        response = client.get("/api/security-incidents?skip=0&limit=10", headers=headers)
        assert response.status_code == 200, f"Expected 200, got {response.status_code}"
        data = response.json()
        assert "total" in data, "Response missing 'total' field"
        assert "incidents" in data, "Response missing 'incidents' field"
        log_test("List security incidents", True)
    except Exception as e:
        log_test("List security incidents", False, str(e))


def test_get_security_incident():
    """Test getting a specific security incident."""
    try:
        if security_incident_id is None:
            raise Exception("No security_incident_id available")
        headers = get_auth_headers()
        response = client.get(f"/api/security-incidents/{security_incident_id}", headers=headers)
        assert response.status_code == 200, f"Expected 200, got {response.status_code}"
        data = response.json()
        assert data["id"] == security_incident_id, f"Expected ID {security_incident_id}, got {data.get('id')}"
        log_test("Get security incident by ID", True)
    except Exception as e:
        log_test("Get security incident by ID", False, str(e))


def test_update_security_incident():
    """Test updating a security incident."""
    try:
        if security_incident_id is None:
            raise Exception("No security_incident_id available")
        headers = get_auth_headers()
        update_data = {
            "status": "resolved",
            "severity": "medium",
            "remediation_steps": "Issue resolved"
        }
        response = client.put(f"/api/security-incidents/{security_incident_id}", json=update_data, headers=headers)
        assert response.status_code == 200, f"Expected 200, got {response.status_code}"
        data = response.json()
        assert data["status"] == "resolved", "Update not reflected"
        log_test("Update security incident", True)
    except Exception as e:
        log_test("Update security incident", False, str(e))


def test_get_security_incidents_by_client():
    """Test getting security incidents by client."""
    try:
        headers = get_auth_headers()
        response = client.get(f"/api/security-incidents/by-client/{work_items_client_id}?skip=0&limit=10", headers=headers)
        assert response.status_code == 200, f"Expected 200, got {response.status_code}"
        data = response.json()
        assert "incidents" in data, "Response missing 'incidents' field"
        log_test("Get security incidents by client", True)
    except Exception as e:
        log_test("Get security incidents by client", False, str(e))


# ============================================================================
# SECTION 13: Cleanup - Delete Test Data
# ============================================================================

print("\n" + "="*70)
print("SECTION 13: Cleanup - Delete Test Data")
print("="*70 + "\n")


def test_cleanup_all_entities():
    """Clean up all created test entities in the correct order."""
    try:
        headers = get_auth_headers()
        cleanup_count = 0

        # Delete in reverse order of dependencies

        # Delete security incidents
        for entity_id in created_entities["security_incidents"]:
            response = client.delete(f"/api/security-incidents/{entity_id}", headers=headers)
            if response.status_code == 200:
                cleanup_count += 1

        # Delete credentials (audit logs remain)
        for entity_id in created_entities["credentials"]:
            response = client.delete(f"/api/credentials/{entity_id}", headers=headers)
            if response.status_code == 200:
                cleanup_count += 1

        # Delete M365 tenants
        for entity_id in created_entities["m365_tenants"]:
            response = client.delete(f"/api/m365-tenants/{entity_id}", headers=headers)
            if response.status_code == 200:
                cleanup_count += 1

        # Delete firewall rules
        for entity_id in created_entities["firewall_rules"]:
            response = client.delete(f"/api/firewall-rules/{entity_id}", headers=headers)
            if response.status_code == 200:
                cleanup_count += 1

        # Delete networks
        for entity_id in created_entities["networks"]:
            response = client.delete(f"/api/networks/{entity_id}", headers=headers)
            if response.status_code == 200:
                cleanup_count += 1

        # Delete services
        for entity_id in created_entities["services"]:
            response = client.delete(f"/api/services/{entity_id}", headers=headers)
            if response.status_code == 200:
                cleanup_count += 1

        # Delete infrastructure
        for entity_id in created_entities["infrastructure"]:
            response = client.delete(f"/api/infrastructure/{entity_id}", headers=headers)
            if response.status_code == 200:
                cleanup_count += 1

        # Delete billable time
        for entity_id in created_entities["billable_time"]:
            response = client.delete(f"/api/billable-time/{entity_id}", headers=headers)
            if response.status_code == 200:
                cleanup_count += 1

        # Delete tasks
        for entity_id in created_entities["tasks"]:
            response = client.delete(f"/api/tasks/{entity_id}", headers=headers)
            if response.status_code == 200:
                cleanup_count += 1

        # Delete work items
        for entity_id in created_entities["work_items"]:
            response = client.delete(f"/api/work-items/{entity_id}", headers=headers)
            if response.status_code == 200:
                cleanup_count += 1

        # Delete sessions
        for entity_id in created_entities["sessions"]:
            response = client.delete(f"/api/sessions/{entity_id}", headers=headers)
            if response.status_code == 200:
                cleanup_count += 1

        # Delete projects
        for entity_id in created_entities["projects"]:
            response = client.delete(f"/api/projects/{entity_id}", headers=headers)
            if response.status_code == 200:
                cleanup_count += 1

        # Delete sites
        for entity_id in created_entities["sites"]:
            response = client.delete(f"/api/sites/{entity_id}", headers=headers)
            if response.status_code == 200:
                cleanup_count += 1

        # Delete clients
        for entity_id in created_entities["clients"]:
            response = client.delete(f"/api/clients/{entity_id}", headers=headers)
            if response.status_code == 200:
                cleanup_count += 1

        print(f"  Cleaned up {cleanup_count} test entities")
        log_test(f"Cleanup all test entities ({cleanup_count} deleted)", True)
    except Exception as e:
        log_test("Cleanup all test entities", False, str(e))


# ============================================================================
# Run All Tests
# ============================================================================

def run_all_tests():
    """Run all test functions."""
    print("\n" + "="*70)
    print("CLAUDETOOLS PHASE 5 API ENDPOINT TESTS")
    print("="*70)

    # Section 1: Work Items
    test_create_work_items_dependencies()
    test_create_work_item()
    test_list_work_items()
    test_get_work_item()
    test_update_work_item()
    test_get_work_items_by_client()

    # Section 2: Tasks
    test_create_task()
    test_list_tasks()
    test_get_task()
    test_update_task()
    test_get_tasks_filtering()

    # Section 3: Billable Time
    test_create_billable_time()
    test_list_billable_time()
    test_get_billable_time()
    test_update_billable_time()
    test_get_billable_time_by_session()

    # Section 4: Sites
    test_create_site()
    test_list_sites()
    test_get_site()
    test_update_site()
    test_get_sites_by_client()

    # Section 5: Infrastructure
    test_create_infrastructure()
    test_list_infrastructure()
    test_get_infrastructure()
    test_update_infrastructure()
    test_get_infrastructure_by_site()

    # Section 6: Services
    test_create_service()
    test_list_services()
    test_get_service()
    test_update_service()
    test_get_services_by_client()

    # Section 7: Networks
    test_create_network()
    test_list_networks()
    test_get_network()
    test_update_network()
    test_get_networks_by_site()

    # Section 8: Firewall Rules
    test_create_firewall_rule()
    test_list_firewall_rules()
    test_get_firewall_rule()
    test_update_firewall_rule()
    test_get_firewall_rules_by_infrastructure()

    # Section 9: M365 Tenants
    test_create_m365_tenant()
    test_list_m365_tenants()
    test_get_m365_tenant()
    test_update_m365_tenant()
    test_get_m365_tenants_by_client()

    # Section 10: Credentials (with encryption)
    test_create_credential_password()
    test_create_credential_api_key()
    test_create_credential_oauth()
    test_list_credentials()
    test_get_credential()
    test_update_credential()
    test_get_credentials_by_client()

    # Section 11: Credential Audit Logs (read-only)
    test_list_credential_audit_logs()
    test_get_credential_audit_logs_by_credential()
    test_get_credential_audit_logs_by_user()

    # Section 12: Security Incidents
    test_create_security_incident()
    test_list_security_incidents()
    test_get_security_incident()
    test_update_security_incident()
    test_get_security_incidents_by_client()

    # Section 13: Cleanup
    test_cleanup_all_entities()


if __name__ == "__main__":
    print("\n>> Starting ClaudeTools Phase 5 API Test Suite...")

    try:
        run_all_tests()

        # Print summary
        print("\n" + "="*70)
        print("TEST SUMMARY")
        print("="*70)
        print(f"\nTotal Tests: {tests_passed + tests_failed}")
        print(f"Passed: {tests_passed}")
        print(f"Failed: {tests_failed}")

        if tests_failed > 0:
            print("\nFAILED TESTS:")
            for name, passed, error in test_results:
                if not passed:
                    print(f"  - {name}")
                    if error:
                        print(f"    Error: {error}")

        if tests_failed == 0:
            print("\n>> All tests passed!")
            sys.exit(0)
        else:
            print(f"\n>> {tests_failed} test(s) failed")
            sys.exit(1)

    except Exception as e:
        print(f"\n>> Fatal error running tests: {e}")
        import traceback
        traceback.print_exc()
        sys.exit(1)
