# Copyright (c) CloudZero - ALL RIGHTS RESERVED - PROPRIETARY AND CONFIDENTIAL
# Unauthorized copying of this file and/or project, via any medium is strictly prohibited.
# Direct all questions to legal@cloudzero.com
#

"""
Simplified authentication command handlers for CloudZero Operations CLI.

This module provides command handlers for:
- czops auth login - Interactive authentication with Okta
- czops auth logout - Clear stored authentication
- czops auth test - Test authentication and show user info
- czops auth test --security - Run comprehensive security tests against auth/verify endpoint
- czops auth refresh - Refresh authentication token
- czops auth userinfo - Show extended user information including groups and metadata
"""

import base64
import json
import sys
import time
from datetime import datetime

import httpx
from rich.console import Console
from rich.panel import Panel
from rich.table import Table

from src.api.authenticated import get_authenticated
from src.auth.simple_auth import AuthenticationError, get_authenticator

console = Console()


def handle_auth_command(arguments: dict) -> None:
    """
    Handle auth subcommands based on parsed arguments.

    Args:
        arguments: Parsed command line arguments from docopt
    """
    try:
        if arguments.get("login"):
            login_command(arguments)
        elif arguments.get("logout"):
            logout_command(arguments)
        elif arguments.get("test"):
            test_command(arguments)
        elif arguments.get("refresh"):
            refresh_command(arguments)
        elif arguments.get("userinfo"):
            userinfo_command(arguments)
        else:
            console.print("[red]Unknown auth command. Use 'czops auth --help' for available commands.[/red]")
            sys.exit(1)

    except KeyboardInterrupt:
        console.print("\n[yellow]Authentication cancelled by user[/yellow]")
        sys.exit(1)
    except AuthenticationError as e:
        console.print(f"[red]Authentication error: {e}[/red]")
        sys.exit(1)
    except Exception as e:
        console.print(f"[red]Unexpected error: {e}[/red]")
        sys.exit(1)


def login_command(arguments: dict) -> None:
    """Handle 'czops auth login' command."""
    console.print(
        Panel.fit("[bold blue]CloudZero Authentication[/bold blue]\nAuthenticating with Okta using OAuth 2.0 PKCE flow", border_style="blue")
    )

    authenticator = get_authenticator()
    force = arguments.get("--force", False)
    debug = arguments.get("--debug", False)

    # Check if already authenticated
    if not force and authenticator.is_authenticated():
        console.print("[green]✓[/green] Already authenticated!")
        _show_token_info(authenticator)

        # Ask if user wants to re-authenticate
        try:
            reauth = console.input("\n[yellow]Re-authenticate anyway? (y/N): [/yellow]").lower()
            if reauth not in ["y", "yes"]:
                return
        except (EOFError, KeyboardInterrupt):
            console.print("\nAuthentication skipped.")
            return

    # Perform authentication
    try:
        token = authenticator.authenticate(force=True, debug=debug)
        access_token = token.get("access_token")

        # Get user info
        user_info = authenticator.get_user_info(access_token)

        console.print("\n[green]✅ Authentication successful![/green]")
        console.print(f"Welcome, {user_info.get('name', 'User')}!")
        console.print(f"Email: {user_info.get('email', 'Unknown')}")

    except AuthenticationError as e:
        console.print(f"\n[red]❌ Authentication failed: {e}[/red]")
        sys.exit(1)


def logout_command(arguments: dict) -> None:
    """Handle 'czops auth logout' command."""
    authenticator = get_authenticator()

    if not authenticator.is_authenticated():
        console.print("[yellow]Not currently authenticated[/yellow]")
        return

    authenticator.clear_token()
    console.print("[green]✓[/green] Successfully logged out")


def test_command(arguments: dict) -> None:
    """Handle 'czops auth test' command."""
    authenticator = get_authenticator()
    debug = arguments.get("--debug", False)
    security = arguments.get("--security", False)

    # If security testing is requested, run security tests instead
    if security:
        _run_security_tests(debug=debug)
        return

    # Try to get a valid access token (this will attempt refresh if needed)
    access_token = authenticator.get_access_token()
    if not access_token:
        console.print("[red]❌ Not authenticated[/red]")
        console.print("Run 'czops auth login' to authenticate")
        sys.exit(1)

    console.print("[green]✅ Locally authenticated[/green]")
    _show_token_info(authenticator)

    # Show cached user information
    _show_userinfo(authenticator, debug=debug)

    # Verify token with backend using /czops/auth/verify endpoint
    try:
        console.print("\n[cyan]Verifying authentication with CloudZero backend...[/cyan]")

        # Use the authenticated API module to call the verify endpoint
        response = get_authenticated(
            endpoint_path="auth/verify",
            debug=debug,
        )

        if response.get("authenticated"):
            # Success case
            console.print(f"\n[green]✅ {response.get('message', 'Authentication successful')}[/green]")
            console.print(f"Email: {response.get('email', 'Unknown')}")
            console.print(f"User ID: {response.get('sub', 'Unknown')}")

            # Show token expiration if available
            if response.get("exp"):
                exp_timestamp = response.get("exp")
                exp_datetime = datetime.fromtimestamp(exp_timestamp)
                console.print(f"Token expires: {exp_datetime.strftime('%Y-%m-%d %H:%M:%S %Z')}")

            console.print("\n[green]✓[/green] Backend API connection verified")
        else:
            # Failure case
            error_msg = response.get("error", "Authentication verification failed")
            console.print(f"\n[red]❌ Backend authentication failed: {error_msg}[/red]")

            # Provide helpful guidance based on the error
            if "expired" in error_msg.lower():
                console.print("\n[yellow]Your token has expired. Please run 'czops auth refresh' to refresh it.[/yellow]")
            elif "invalid" in error_msg.lower():
                console.print("\n[yellow]Your token appears to be invalid. Please run 'czops auth login' to re-authenticate.[/yellow]")

            sys.exit(1)

    except ValueError as e:
        # Handle authentication errors (not authenticated, no token, etc.)
        console.print(f"\n[red]❌ Authentication error: {e}[/red]")
        console.print("[yellow]Please run 'czops auth login' to authenticate.[/yellow]")
        sys.exit(1)
    except httpx.HTTPStatusError as e:
        # Handle HTTP errors (401, 403, etc.)
        console.print(f"\n[red]❌ Authentication verification failed: HTTP {e.response.status_code}[/red]")
        if e.response.status_code == 401:
            console.print("[yellow]Your token is invalid or expired. Please run 'czops auth refresh' or 'czops auth login'.[/yellow]")
        elif e.response.status_code == 403:
            console.print("[yellow]Access denied. Please check your permissions.[/yellow]")
        else:
            console.print(f"[yellow]Server response: {e.response.text}[/yellow]")
        sys.exit(1)
    except Exception as e:
        console.print(f"\n[red]❌ Failed to verify authentication: {e}[/red]")
        console.print("[yellow]Please check your network connection and try again.[/yellow]")
        sys.exit(1)


def refresh_command(arguments: dict) -> None:
    """Handle 'czops auth refresh' command."""
    authenticator = get_authenticator()

    if not authenticator.is_authenticated():
        console.print("[red]❌ Not authenticated[/red]")
        console.print("Run 'czops auth login' to authenticate")
        sys.exit(1)

    token = authenticator.get_stored_token()
    if not token or "refresh_token" not in token:
        console.print("[red]❌ No refresh token available[/red]")
        console.print("Run 'czops auth login' to re-authenticate")
        sys.exit(1)

    try:
        console.print("🔄 Refreshing authentication token...")
        authenticator.refresh_token(token["refresh_token"])
        console.print("[green]✅ Token refreshed successfully[/green]")
        _show_token_info(authenticator)
    except AuthenticationError as e:
        console.print(f"[red]❌ Token refresh failed: {e}[/red]")
        console.print("Run 'czops auth login' to re-authenticate")
        sys.exit(1)


def userinfo_command(arguments: dict) -> None:
    """Handle 'czops auth userinfo' command to show extended user information."""
    authenticator = get_authenticator()
    debug = arguments.get("--debug", False)

    # Check if authenticated
    if not authenticator.is_authenticated():
        console.print("[red]❌ Not authenticated[/red]")
        console.print("Run 'czops auth login' to authenticate")
        sys.exit(1)

    try:
        console.print("[cyan]📋 Gathering extended user information...[/cyan]")
        # Get extended user info
        extended_info = authenticator.get_extended_user_info()

        if debug:
            # Show complete raw data in debug mode
            console.print("\n[yellow]DEBUG: Complete Extended User Information[/yellow]")
            console.print(json.dumps(extended_info, indent=2))
            console.print()

            # Show JWT token information in debug mode
            _show_jwt_debug_info(authenticator)

        # Display formatted user information
        table = Table(title="Extended User Information")
        table.add_column("Property", style="cyan")
        table.add_column("Value", style="green")

        # Basic profile info
        table.add_row("Full Name", extended_info.get("name", "Unknown"))
        table.add_row("Email", extended_info.get("email", "Unknown"))
        table.add_row("Given Name", extended_info.get("given_name", "Unknown"))
        table.add_row("Family Name", extended_info.get("family_name", "Unknown"))
        table.add_row("Preferred Username", extended_info.get("preferred_username", "Unknown"))

        # Extended metadata from backend
        if extended_info.get("user_department"):
            table.add_row("Department", extended_info.get("user_department"))
        if extended_info.get("user_title"):
            table.add_row("Title", extended_info.get("user_title"))
        if extended_info.get("user_full_name"):
            table.add_row("Full Name (Backend)", extended_info.get("user_full_name"))

        # Group information from different sources
        backend_groups = extended_info.get("user_groups", [])
        okta_groups = extended_info.get("groups", [])
        access_token_groups = extended_info.get("groups_from_access_token", [])
        id_token_groups = extended_info.get("groups_from_id_token", [])
        jwt_groups = extended_info.get("groups_from_jwt", [])

        # Create combined set of all groups
        all_groups = set(backend_groups + okta_groups + access_token_groups + id_token_groups + jwt_groups)
        combined_groups = sorted(list(all_groups))

        # Optional: Filter groups to only show those starting with "Team"
        # Uncomment the next line to only show Team groups:
        # combined_groups = [group for group in combined_groups if group.startswith("Team")]

        # Display single combined group list
        if combined_groups:
            table.add_row("User Groups", ", ".join(combined_groups))
        else:
            table.add_row("User Groups", "None")

        # Technical info
        table.add_row("Okta User ID", extended_info.get("uid", "Unknown"))
        table.add_row("Backend User ID", extended_info.get("backend_user_id", "Unknown"))
        table.add_row("OAuth Scopes", ", ".join(extended_info.get("scp", [])))
        table.add_row("Timezone", extended_info.get("zoneinfo", "Unknown"))
        table.add_row("Locale", extended_info.get("locale", "Unknown"))
        table.add_row("Email Verified", "Yes" if extended_info.get("email_verified") else "No")

        console.print(table)

        # Group sources and consistency analysis
        console.print("\n[cyan]📋 Group Information Analysis:[/cyan]")

        # Determine which sources have group data
        group_sources = []
        source_groups = {}

        if backend_groups:
            group_sources.append("Backend API")
            source_groups["Backend API"] = set(backend_groups)
        if okta_groups:
            group_sources.append("Okta UserInfo")
            source_groups["Okta UserInfo"] = set(okta_groups)
        if access_token_groups:
            group_sources.append("Access Token")
            source_groups["Access Token"] = set(access_token_groups)
        if id_token_groups:
            group_sources.append("ID Token")
            source_groups["ID Token"] = set(id_token_groups)
        if jwt_groups:
            group_sources.append("JWT Combined")
            source_groups["JWT Combined"] = set(jwt_groups)

        # Display sources
        if group_sources:
            console.print(f"[dim]Group Sources:[/dim] {', '.join(group_sources)}")
        else:
            console.print("[dim]Group Sources:[/dim] None")

        # Check consistency across sources
        consistency_check = "Yes"
        if len(source_groups) > 1:
            # Compare all source groups to see if they're identical
            first_source_groups = next(iter(source_groups.values()))
            for source_name, groups in source_groups.items():
                if groups != first_source_groups:
                    consistency_check = "No"
                    break
        elif len(source_groups) == 0:
            consistency_check = "N/A (no group data)"
        elif len(source_groups) == 1:
            consistency_check = "N/A (single source)"

        console.print(f"[dim]Groups Identical Across Sources:[/dim] {consistency_check}")

        # Summary message
        total_groups = len(combined_groups)
        console.print("\n[green]✅ Extended user information retrieved successfully[/green]")
        console.print(f"[dim]Groups found: {total_groups} • Sources: {len(group_sources)}[/dim]")

    except AuthenticationError as e:
        console.print(f"[red]❌ Authentication error: {e}[/red]")
        console.print("[yellow]Please run 'czops auth login' to re-authenticate.[/yellow]")
        sys.exit(1)
    except Exception as e:
        console.print(f"[red]❌ Failed to get extended user info: {e}[/red]")
        if debug:
            import traceback

            console.print(f"[red]Traceback: {traceback.format_exc()}[/red]")
        sys.exit(1)


def _show_token_info(authenticator):
    """Display token information in a table."""
    token = authenticator.get_stored_token()
    if not token:
        return

    table = Table(title="Authentication Status")
    table.add_column("Property", style="cyan")
    table.add_column("Value", style="green")

    # Calculate time until expiry
    if "expires_at" in token:
        expires_at = datetime.fromisoformat(token["expires_at"].replace("Z", "+00:00"))
        time_left = expires_at - datetime.now(expires_at.tzinfo)

        if time_left.total_seconds() > 0:
            hours = int(time_left.total_seconds() // 3600)
            minutes = int((time_left.total_seconds() % 3600) // 60)
            time_str = f"{hours}h {minutes}m"
            expires_str = expires_at.strftime("%Y-%m-%d %H:%M:%S %Z")
        else:
            time_str = "Expired"
            expires_str = "Token has expired"
    else:
        time_str = "Unknown"
        expires_str = "Unknown"

    table.add_row("Status", "✓ Valid" if authenticator.is_token_valid(token) else "✗ Invalid")
    table.add_row("Expires", expires_str)
    table.add_row("Time Until Expiry", time_str)
    table.add_row("Has Refresh Token", "Yes" if "refresh_token" in token else "No")

    console.print(table)


def _show_userinfo(authenticator, debug=False):
    """Display cached user information."""
    userinfo = authenticator.get_cached_userinfo()
    if not userinfo:
        if debug:
            console.print("\n[yellow]No cached user information available[/yellow]")
        return

    if debug:
        # In debug mode, show the complete raw userinfo object
        console.print("\n[yellow]DEBUG: Complete User Information Object[/yellow]")
        import json

        console.print(json.dumps(userinfo, indent=2))
        console.print()  # Extra line for spacing
    else:
        # In normal mode, show formatted table with core info
        table = Table(title="User Information")
        table.add_column("Property", style="cyan")
        table.add_column("Value", style="green")

        # Core user info
        table.add_row("Full Name", userinfo.get("name", "Unknown"))
        table.add_row("Email", userinfo.get("email", "Unknown"))
        table.add_row("Given Name", userinfo.get("given_name", "Unknown"))
        table.add_row("Family Name", userinfo.get("family_name", "Unknown"))
        table.add_row("Preferred Username", userinfo.get("preferred_username", "Unknown"))
        table.add_row("Timezone", userinfo.get("zoneinfo", "Unknown"))
        table.add_row("Locale", userinfo.get("locale", "Unknown"))
        table.add_row("Email Verified", "Yes" if userinfo.get("email_verified") else "No")

        console.print(table)


def _show_jwt_debug_info(authenticator):
    """Display detailed JWT token information for debugging."""

    # Get stored token
    token = authenticator.get_stored_token()
    if not token:
        console.print("\n[red]No stored token available[/red]")
        return

    console.print("\n[yellow]DEBUG: JWT Token Information[/yellow]")
    console.print("─" * 80)

    # Display Access Token
    access_token = token.get("access_token")
    if access_token:
        console.print("\n[cyan]Access Token:[/cyan]")
        _decode_and_display_jwt(access_token, "Access Token")
    else:
        console.print("\n[red]No Access Token found[/red]")

    # Display ID Token if present
    id_token = token.get("id_token")
    if id_token:
        console.print("\n[cyan]ID Token:[/cyan]")
        _decode_and_display_jwt(id_token, "ID Token")
    else:
        console.print("\n[yellow]No ID Token found in stored token[/yellow]")

    # Show refresh token info
    refresh_token = token.get("refresh_token")
    if refresh_token:
        console.print(f"\n[cyan]Refresh Token:[/cyan] Present (length: {len(refresh_token)})")
    else:
        console.print("\n[yellow]No Refresh Token found[/yellow]")

    console.print("─" * 80)


def _decode_and_display_jwt(jwt_token, token_type=None):
    """Decode and display JWT token contents."""
    import base64
    import json

    # Use a default label if not provided
    display_name = token_type or "Token"

    try:
        # Split JWT into parts
        parts = jwt_token.split(".")
        if len(parts) != 3:
            console.print(f"[red]Invalid JWT format: expected 3 parts, got {len(parts)}[/red]")
            return

        # Decode header
        header_data = parts[0] + "=" * (4 - len(parts[0]) % 4)  # Add padding
        header = json.loads(base64.urlsafe_b64decode(header_data))

        # Decode payload
        payload_data = parts[1] + "=" * (4 - len(parts[1]) % 4)  # Add padding
        payload = json.loads(base64.urlsafe_b64decode(payload_data))

        # Display header
        console.print("  [bold]Header:[/bold]")
        console.print(f"    {json.dumps(header, indent=4)}")

        # Display payload
        console.print("  [bold]Payload:[/bold]")
        console.print(f"    {json.dumps(payload, indent=4, default=str)}")

        # Show signature info
        signature = parts[2]
        console.print(f"  [bold]Signature:[/bold] Present (length: {len(signature)})")

        # Highlight interesting claims
        interesting_claims = []
        if "groups" in payload:
            interesting_claims.append(f"Groups: {payload['groups']}")
        if "scp" in payload:
            interesting_claims.append(f"Scopes: {payload['scp']}")
        if "aud" in payload:
            interesting_claims.append(f"Audience: {payload['aud']}")
        if "iss" in payload:
            interesting_claims.append(f"Issuer: {payload['iss']}")
        if "exp" in payload:
            from datetime import datetime

            exp_time = datetime.fromtimestamp(payload["exp"])
            interesting_claims.append(f"Expires: {exp_time}")

        if interesting_claims:
            console.print("  [bold]Key Claims:[/bold]")
            for claim in interesting_claims:
                console.print(f"    • {claim}")

    except Exception as e:
        console.print(f"[red]Failed to decode {display_name}: {e}[/red]")


def _run_security_tests(debug: bool = False) -> None:
    """
    Run comprehensive security tests against the auth/verify endpoint.

    This function tests various attack vectors including:
    - Invalid JWT tokens
    - Malformed headers
    - Injection attempts
    - Privilege escalation attempts
    - Token manipulation
    """
    from src.settings import Settings

    settings = Settings()
    api_url = f"{settings.api_v4.endpoint}v4/auth/verify"

    console.print(
        Panel.fit(
            "[bold red]🔒 SECURITY TESTING MODE[/bold red]\n"
            f"Target Endpoint: [cyan]{api_url}[/cyan]\n"
            f"User ID: [cyan]{settings.email}[/cyan]\n"
            "Testing authentication security with malicious inputs\n"
            "[yellow]⚠️  This will generate many unauthorized requests - this is expected behavior[/yellow]",
            border_style="red",
        )
    )

    console.print(f"\n[bold]🎯 Target Endpoint:[/bold] {api_url}")
    console.print(f"[bold]👤 User ID:[/bold] {settings.email}")
    console.print("[bold]📋 Test Objective:[/bold] Verify that unauthorized requests are properly rejected")
    console.print(
        "[bold]✅ Expected Behavior:[/bold] All malicious requests should return 400 Bad Request, 401 Unauthorized, 403 Forbidden, or 413 Request Entity Too Large"
    )
    console.print("[bold]❌ Security Issue:[/bold] Any 200 OK responses indicate potential vulnerabilities\n")

    # Security test results - using security terminology
    results = {"secure": 0, "vulnerable": 0, "errors": 0, "vulnerabilities": [], "tests": []}

    # Test categories
    test_categories = [
        ("Invalid JWT Tokens", _test_invalid_jwt_tokens, "Testing malformed and invalid JWT tokens"),
        ("Malformed Headers", _test_malformed_headers, "Testing authentication header manipulation"),
        ("Injection Attacks", _test_injection_attacks, "Testing code injection via JWT claims"),
        ("Privilege Escalation", _test_privilege_escalation, "Testing unauthorized privilege claims"),
        ("Token Manipulation", _test_token_manipulation, "Testing JWT algorithm confusion and tampering"),
        ("Authentication Bypass", _test_auth_bypass, "Testing alternative authentication methods"),
    ]

    for category_name, test_func, description in test_categories:
        console.print(f"\n[bold blue]🧪 {category_name}[/bold blue]")
        console.print(f"[dim]{description}[/dim]")
        console.print("─" * 80)

        category_results = test_func(api_url, debug)
        results["tests"].extend(category_results)

        # Count results using security terminology
        category_secure = 0
        category_vulnerable = 0
        category_errors = 0

        for test in category_results:
            if test["status"] == "SECURE":
                results["secure"] += 1
                category_secure += 1
            elif test["status"] == "VULNERABLE":
                results["vulnerable"] += 1
                category_vulnerable += 1
                results["vulnerabilities"].append(test)
            else:
                results["errors"] += 1
                category_errors += 1

        # Show category summary
        if category_vulnerable > 0:
            console.print(f"[red]⚠️  Category Result: {category_vulnerable} VULNERABILITIES DETECTED[/red]")
        elif category_errors > 0:
            console.print(f"[yellow]⚠️  Category Result: {category_errors} errors, {category_secure} secure[/yellow]")
        else:
            console.print(f"[green]✅ Category Result: All {category_secure} tests SECURE[/green]")

    # Display final results
    _display_security_results(results, debug)


def _test_invalid_jwt_tokens(api_url: str, debug: bool) -> list[dict]:
    """Test various invalid JWT token scenarios."""
    tests = []

    # Test cases for invalid JWT tokens
    invalid_tokens = [
        ("Empty token", ""),
        ("Invalid format", "not.a.jwt"),
        ("Too many parts", "header.payload.signature.extra"),
        ("Too few parts", "header.payload"),
        ("Invalid base64", "invalid_base64.invalid_base64.invalid_base64"),
        ("Null bytes", "header\x00.payload\x00.signature\x00"),
        ("Extremely long token", "A" * 10000),
        ("SQL injection attempt", "'; DROP TABLE users; --"),
        ("XSS attempt", "<script>alert('xss')</script>"),
        ("Directory traversal", "../../../etc/passwd"),
        ("Command injection", "; cat /etc/passwd"),
        ("LDAP injection", "admin)(|(password=*)"),
        ("NoSQL injection", "admin'||'1'=='1"),
    ]

    for test_name, token in invalid_tokens:
        full_test_name = f"Invalid JWT: {test_name}"
        headers = {"Authorization": f"Bearer {token}"}

        # Show test details
        console.print(f"[dim]  🔍 {full_test_name}[/dim]")
        console.print(f"[dim]     Request: POST {api_url}[/dim]")
        console.print(f"[dim]     Token: {repr(token)[:50]}{'...' if len(repr(token)) > 50 else ''}[/dim]")

        test_result = _make_security_test_request(api_url=api_url, headers=headers, test_name=full_test_name, expected_status=401, debug=debug)
        tests.append(test_result)

    return tests


def _test_malformed_headers(api_url: str, debug: bool) -> list[dict]:
    """Test various malformed header scenarios."""
    tests = []

    # Test cases for malformed headers
    header_tests = [
        ("Missing Authorization header", {}),
        ("Wrong auth scheme", {"Authorization": "Basic dGVzdDp0ZXN0"}),
        ("Malformed Bearer", {"Authorization": "Bearer"}),
        ("Extra Bearer", {"Authorization": "Bearer Bearer token"}),
        ("Case variations", {"authorization": "bearer token"}),
        ("Null bytes in header", {"Authorization": "Bearer token\x00"}),
        ("Unicode injection", {"Authorization": "Bearer token\u0000\u202e"}),
        ("Header injection", {"Authorization": "Bearer token\r\nX-Admin: true"}),
        ("Extremely long header", {"Authorization": f"Bearer {'A' * 50000}"}),
        ("Multiple auth headers", {"Authorization": "Bearer token1", "X-Authorization": "Bearer token2"}),
    ]

    for test_name, headers in header_tests:
        full_test_name = f"Malformed Headers: {test_name}"

        # Show test details
        console.print(f"[dim]  🔍 {full_test_name}[/dim]")
        console.print(f"[dim]     Request: POST {api_url}[/dim]")
        if headers:
            for key, value in headers.items():
                display_value = str(value)[:50] + ("..." if len(str(value)) > 50 else "")
                console.print(f"[dim]     Header: {key}: {display_value}[/dim]")
        else:
            console.print("[dim]     Headers: None (testing missing auth header)[/dim]")

        test_result = _make_security_test_request(api_url=api_url, headers=headers, test_name=full_test_name, expected_status=401, debug=debug)
        tests.append(test_result)

    return tests


def _test_injection_attacks(api_url: str, debug: bool) -> list[dict]:
    """Test various injection attack scenarios."""
    tests = []

    # Create a fake but properly formatted JWT for injection tests
    fake_payload = {"sub": "injection_test", "email": "test@example.com", "exp": int(time.time()) + 3600, "iat": int(time.time())}

    # Base64 encode the payload (note: this won't have a valid signature)
    header = base64.urlsafe_b64encode(json.dumps({"alg": "none", "typ": "JWT"}).encode()).decode().rstrip("=")

    injection_payloads = [
        ("SQL injection in sub", {"sub": "'; DROP TABLE users; --"}),
        ("XSS in email", {"email": "<script>alert('xss')</script>@test.com"}),
        ("Command injection in email", {"email": "; cat /etc/passwd @test.com"}),
        ("LDAP injection in sub", {"sub": "admin)(|(password=*)"}),
        ("NoSQL injection in email", {"email": "admin'||'1'=='1@test.com"}),
        ("JSON injection", {"email": '"}; system("rm -rf /"); {"a": "b@test.com'}),
        ("Path traversal in sub", {"sub": "../../../etc/passwd"}),
        ("Null bytes in claims", {"sub": "user\x00", "email": "test\x00@test.com"}),
    ]

    for test_name, malicious_payload in injection_payloads:
        # Create the malicious payload
        payload = {**fake_payload, **malicious_payload}
        payload_b64 = base64.urlsafe_b64encode(json.dumps(payload).encode()).decode().rstrip("=")
        malicious_token = f"{header}.{payload_b64}.fake_signature"

        full_test_name = f"Injection Attack: {test_name}"

        # Show test details
        console.print(f"[dim]  🔍 {full_test_name}[/dim]")
        console.print(f"[dim]     Request: POST {api_url}[/dim]")
        console.print(f"[dim]     Attack Vector: {list(malicious_payload.keys())[0]} = {repr(list(malicious_payload.values())[0])[:50]}[/dim]")
        console.print(f"[dim]     JWT Payload: {json.dumps(payload, separators=(',', ':'))[:80]}...[/dim]")

        test_result = _make_security_test_request(
            api_url=api_url,
            headers={"Authorization": f"Bearer {malicious_token}"},
            test_name=full_test_name,
            expected_status=401,
            debug=debug,
        )
        tests.append(test_result)

    return tests


def _test_privilege_escalation(api_url: str, debug: bool) -> list[dict]:
    """Test privilege escalation attempts."""
    tests = []

    # Create fake tokens with elevated privileges
    fake_payload_base = {"sub": "malicious_user", "email": "attacker@example.com", "exp": int(time.time()) + 3600, "iat": int(time.time())}

    header = base64.urlsafe_b64encode(json.dumps({"alg": "none", "typ": "JWT"}).encode()).decode().rstrip("=")

    privilege_tests = [
        ("Admin role claim", {"role": "admin", "admin": True}),
        ("Super user claim", {"superuser": True, "is_admin": True}),
        ("Root access claim", {"user": "root", "uid": 0}),
        ("System user claim", {"user": "system", "privileges": ["all"]}),
        ("CloudZero admin", {"email": "admin@cloudzero.com", "role": "super_admin"}),
        ("Elevated permissions", {"permissions": ["read", "write", "delete", "admin"]}),
        ("Scope manipulation", {"scope": "admin read write delete"}),
        ("Audience manipulation", {"aud": "admin-service"}),
        ("Issuer spoofing", {"iss": "trusted-issuer", "admin": True}),
    ]

    for test_name, privilege_claims in privilege_tests:
        payload = {**fake_payload_base, **privilege_claims}
        payload_b64 = base64.urlsafe_b64encode(json.dumps(payload).encode()).decode().rstrip("=")
        malicious_token = f"{header}.{payload_b64}.fake_signature"

        full_test_name = f"Privilege Escalation: {test_name}"

        # Show test details
        console.print(f"[dim]  🔍 {full_test_name}[/dim]")
        console.print(f"[dim]     Request: POST {api_url}[/dim]")
        console.print(f"[dim]     Privilege Claims: {json.dumps(privilege_claims, separators=(',', ':'))[:60]}[/dim]")
        console.print(f"[dim]     Attempting to gain: {', '.join(str(k) for k in privilege_claims)}[/dim]")

        test_result = _make_security_test_request(
            api_url=api_url,
            headers={"Authorization": f"Bearer {malicious_token}"},
            test_name=full_test_name,
            expected_status=401,
            debug=debug,
        )
        tests.append(test_result)

    return tests


def _test_token_manipulation(api_url: str, debug: bool) -> list[dict]:
    """Test token manipulation scenarios."""
    tests = []

    # Create a base token
    header = base64.urlsafe_b64encode(json.dumps({"alg": "HS256", "typ": "JWT"}).encode()).decode().rstrip("=")
    payload = {"sub": "test_user", "email": "test@cloudzero.com", "exp": int(time.time()) + 3600, "iat": int(time.time())}
    payload_b64 = base64.urlsafe_b64encode(json.dumps(payload).encode()).decode().rstrip("=")

    manipulation_tests = [
        (
            "Algorithm confusion (none)",
            base64.urlsafe_b64encode(json.dumps({"alg": "none", "typ": "JWT"}).encode()).decode().rstrip("=") + f".{payload_b64}.",
        ),
        (
            "Algorithm confusion (HS256 to RS256)",
            base64.urlsafe_b64encode(json.dumps({"alg": "RS256", "typ": "JWT"}).encode()).decode().rstrip("=") + f".{payload_b64}.fake_signature",
        ),
        (
            "Modified expiration",
            f"{header}."
            + base64.urlsafe_b64encode(json.dumps({**payload, "exp": int(time.time()) + 86400 * 365}).encode()).decode().rstrip("=")
            + ".fake_signature",
        ),
        (
            "Null algorithm",
            base64.urlsafe_b64encode(json.dumps({"alg": None, "typ": "JWT"}).encode()).decode().rstrip("=") + f".{payload_b64}.fake_signature",
        ),
        ("Empty signature", f"{header}.{payload_b64}."),
        ("Modified signature", f"{header}.{payload_b64}.modified_signature"),
        ("Swapped header/payload", f"{payload_b64}.{header}.fake_signature"),
    ]

    for test_name, token in manipulation_tests:
        full_test_name = f"Token Manipulation: {test_name}"

        # Show test details
        console.print(f"[dim]  🔍 {full_test_name}[/dim]")
        console.print(f"[dim]     Request: POST {api_url}[/dim]")
        console.print(f"[dim]     Manipulation: {test_name}[/dim]")
        console.print(f"[dim]     Token: {token[:60]}{'...' if len(token) > 60 else ''}[/dim]")

        test_result = _make_security_test_request(
            api_url=api_url,
            headers={"Authorization": f"Bearer {token}"},
            test_name=full_test_name,
            expected_status=401,
            debug=debug,
        )
        tests.append(test_result)

    return tests


def _test_auth_bypass(api_url: str, debug: bool) -> list[dict]:
    """Test authentication bypass attempts."""
    tests = []

    bypass_tests = [
        ("No authentication", {}),
        ("Alternative auth headers", {"X-Auth-Token": "test", "X-API-Key": "test"}),
        ("Basic auth fallback", {"Authorization": "Basic YWRtaW46cGFzc3dvcmQ="}),
        ("Custom auth headers", {"X-CloudZero-Auth": "bypass", "X-Internal-Auth": "true"}),
        ("Session cookies", {}, {"session": "admin_session", "auth": "true"}),
        ("IP-based bypass", {"X-Forwarded-For": "127.0.0.1", "X-Real-IP": "localhost"}),
        ("User-Agent bypass", {"User-Agent": "CloudZero-Internal-Service"}),
        ("Origin bypass", {"Origin": "https://cloudzero.com", "Referer": "https://cloudzero.com"}),
        ("Method override", {"X-HTTP-Method-Override": "GET"}, None, "GET"),
        ("Admin endpoints", {}),  # This will test without auth on what should be a protected endpoint
    ]

    for item in bypass_tests:
        if len(item) == 2:
            test_name, headers = item
            cookies = None
            method = "POST"
        elif len(item) == 3:
            test_name, headers, cookies = item
            method = "POST"
        else:
            test_name, headers, cookies, method = item

        full_test_name = f"Auth Bypass: {test_name}"

        # Show test details
        console.print(f"[dim]  🔍 {full_test_name}[/dim]")
        console.print(f"[dim]     Request: {method} {api_url}[/dim]")
        if headers:
            for key, value in headers.items():
                display_value = str(value)[:40] + ("..." if len(str(value)) > 40 else "")
                console.print(f"[dim]     Header: {key}: {display_value}[/dim]")
        if cookies:
            console.print(f"[dim]     Cookies: {json.dumps(cookies, separators=(',', ':'))[:50]}[/dim]")
        if not headers and not cookies:
            console.print("[dim]     Auth: None (testing bypass without authentication)[/dim]")

        test_result = _make_security_test_request(
            api_url=api_url, headers=headers, cookies=cookies, method=method, test_name=full_test_name, expected_status=401, debug=debug
        )
        tests.append(test_result)

    return tests


def _make_security_test_request(
    api_url: str,
    headers: dict = None,
    cookies: dict = None,
    method: str = "POST",
    test_name: str = "",
    expected_status: int = 401,
    debug: bool = False,
) -> dict:
    """
    Make a security test request and evaluate the response.

    Returns a test result dictionary with status, details, etc.
    """
    # Add standard headers that should always be present
    final_headers = {
        "Content-Type": "application/json",
    }

    if headers:
        final_headers.update(headers)

    test_result = {
        "test_name": test_name,
        "status": "UNKNOWN",
        "response_status": None,
        "response_body": None,
        "vulnerability_details": None,
        "request_headers": final_headers.copy(),
        "request_method": method,
        "request_url": api_url,
    }

    try:
        with httpx.Client(timeout=10) as client:
            response = client.request(method=method, url=api_url, headers=final_headers, cookies=cookies, json={} if method == "POST" else None)

            test_result["response_status"] = response.status_code
            test_result["response_headers"] = dict(response.headers)

            try:
                test_result["response_body"] = response.json()
            except Exception:
                test_result["response_body"] = response.text[:500]  # Truncate long responses

            # Evaluate security implications using proper security terminology
            # 400, 401, 403, and 413 are all secure responses indicating proper request validation
            if response.status_code in [400, 401, 403, 413]:
                test_result["status"] = "SECURE"
                console.print(f"[green]     ✅ SECURE[/green] - HTTP {response.status_code} {response.reason_phrase}")
            elif response.status_code == 200:
                # This is a vulnerability - unauthorized access succeeded
                test_result["status"] = "VULNERABLE"
                test_result["vulnerability_details"] = (
                    "🚨 CRITICAL VULNERABILITY: Request succeeded with HTTP 200 when 400/401/403/413 was expected. "
                    "This indicates an authentication bypass vulnerability allowing unauthorized access."
                )
                console.print(f"[bold red]     🚨 VULNERABLE[/bold red] - HTTP {response.status_code} {response.reason_phrase}")
                console.print("[red]     💥 SECURITY BREACH: Unauthorized request was accepted![/red]")

                # Show detailed failure information immediately
                _show_vulnerability_details(test_result)

            elif response.status_code in [500, 502, 503]:
                # Server errors might indicate injection succeeded
                test_result["status"] = "VULNERABLE"
                test_result["vulnerability_details"] = (
                    f"⚠️ POTENTIAL VULNERABILITY: Server error ({response.status_code}) may indicate successful "
                    f"injection attack or denial of service vulnerability."
                )
                console.print(f"[yellow]     ⚠️  POTENTIAL ISSUE[/yellow] - HTTP {response.status_code} {response.reason_phrase}")
                console.print("[yellow]     Server error may indicate successful attack[/yellow]")
            else:
                test_result["status"] = "UNEXPECTED"
                test_result["vulnerability_details"] = f"Unexpected status code {response.status_code} - requires investigation"
                console.print(f"[yellow]     ❓ UNEXPECTED[/yellow] - HTTP {response.status_code} {response.reason_phrase}")

    except httpx.TimeoutException:
        test_result["status"] = "TIMEOUT"
        test_result["vulnerability_details"] = "Request timed out - may indicate DoS vulnerability or server overload"
        console.print("[yellow]     ⏱️  TIMEOUT[/yellow] - Request timed out")
    except (
        httpx.InvalidURL,
        httpx.UnsupportedProtocol,
        httpx.RequestError,  # Base class for httpx request errors
        ValueError,
        UnicodeError,
        UnicodeDecodeError,
        UnicodeEncodeError,
        OSError,  # May be raised for invalid headers
        TypeError,  # May be raised for invalid header types
    ) as e:
        # These exceptions indicate client-side validation working correctly - this is SECURE
        test_result["status"] = "SECURE"
        test_result["vulnerability_details"] = f"Client-side validation rejected malformed request: {str(e)}"
        console.print(f"[green]     ✅ SECURE[/green] - Client blocked malformed request: {str(e)}")
    except Exception as e:
        # Other unexpected errors that might indicate real issues
        test_result["status"] = "ERROR"
        test_result["vulnerability_details"] = f"Unexpected request failure: {str(e)}"
        console.print(f"[red]     ❌ ERROR[/red] - {str(e)}")

    return test_result


def _show_vulnerability_details(test_result: dict) -> None:
    """Show detailed information about a security vulnerability."""
    console.print("[red]     🔍 VULNERABILITY DETAILS:[/red]")
    console.print(f"[red]       Request: {test_result['request_method']} {test_result['request_url']}[/red]")

    # Show request headers (mask sensitive data)
    for key, value in test_result["request_headers"].items():
        display_value = (f"{str(value)[:20]}..." if len(str(value)) > 20 else str(value)) if key.lower() == "authorization" else str(value)
        console.print(f"[red]       Request Header: {key}: {display_value}[/red]")

    console.print(f"[red]       Response: HTTP {test_result['response_status']}[/red]")
    console.print(
        f"[red]       Response Body: {str(test_result['response_body'])[:100]}{'...' if len(str(test_result['response_body'])) > 100 else ''}[/red]"
    )
    console.print(f"[red]       Impact: {test_result['vulnerability_details']}[/red]")
    console.print()


def _display_security_results(results: dict, debug: bool) -> None:
    """Display comprehensive security test results using proper security terminology."""

    # Summary panel using security terminology
    total_tests = len(results["tests"])
    secure_tests = results["secure"]
    vulnerable_tests = results["vulnerable"]
    error_tests = results["errors"]
    vulnerabilities = len(results["vulnerabilities"])

    console.print("\n" + "═" * 80)
    console.print("[bold]🔒 SECURITY TEST RESULTS[/bold]")
    console.print("═" * 80)

    summary_text = f"""
    [green]🛡️  SECURE: {secure_tests}[/green] - Properly rejected unauthorized requests
    [red]🚨 VULNERABLE: {vulnerable_tests}[/red] - Security issues detected
    [yellow]⚠️  ERRORS: {error_tests}[/yellow] - Tests had technical issues
    [cyan]📊 TOTAL TESTS: {total_tests}[/cyan]
    """

    # Determine overall security status
    if vulnerable_tests == 0 and error_tests == 0:
        summary_text += "\n[bold green]✅ SECURITY STATUS: SYSTEM IS SECURE[/bold green]"
        summary_text += "\n[green]All unauthorized requests were properly rejected![/green]"
        border_style = "green"
        status_message = "🛡️  SECURITY TESTS PASSED"
    elif vulnerable_tests > 0:
        summary_text += "\n[bold red]❌ SECURITY STATUS: VULNERABILITIES DETECTED[/bold red]"
        summary_text += f"\n[red]{vulnerable_tests} critical security issue{'s' if vulnerable_tests != 1 else ''} found![/red]"
        border_style = "red"
        status_message = "🚨 SECURITY TESTS FAILED"
    else:
        summary_text += "\n[bold yellow]⚠️  SECURITY STATUS: INCONCLUSIVE[/bold yellow]"
        summary_text += f"\n[yellow]{error_tests} test{'s' if error_tests != 1 else ''} had technical issues - manual review needed[/yellow]"
        border_style = "yellow"
        status_message = "⚠️  SECURITY TESTS INCONCLUSIVE"

    console.print(Panel(summary_text, title=status_message, border_style=border_style))

    # Detailed vulnerability report
    if vulnerabilities > 0:
        console.print("\n[bold red]🚨 CRITICAL SECURITY VULNERABILITIES:[/bold red]")
        console.print("[red]The following tests FAILED, indicating potential security breaches:[/red]\n")

        vuln_table = Table(title="Security Vulnerabilities Found", border_style="red")
        vuln_table.add_column("Failed Test", style="cyan", width=30)
        vuln_table.add_column("Response", style="yellow", width=12)
        vuln_table.add_column("Security Impact", style="red", width=50)

        for vuln in results["vulnerabilities"]:
            vuln_table.add_row(
                vuln["test_name"],
                f"HTTP {vuln['response_status']}",
                vuln["vulnerability_details"][:50] + ("..." if len(vuln["vulnerability_details"]) > 50 else ""),
            )

        console.print(vuln_table)

        console.print("\n[bold red]⚠️  IMMEDIATE ACTION REQUIRED:[/bold red]")
        console.print("[red]• Review and fix the authentication system immediately[/red]")
        console.print("[red]• These vulnerabilities allow unauthorized access to the system[/red]")
        console.print("[red]• Contact your security team for immediate remediation[/red]")

    # Show detailed test breakdown if requested
    if debug:
        console.print("\n[yellow]📋 DETAILED TEST BREAKDOWN:[/yellow]")

        detail_table = Table(title="Complete Test Results", border_style="blue")
        detail_table.add_column("Test Name", style="cyan", width=35)
        detail_table.add_column("Status", style="white", width=12)
        detail_table.add_column("HTTP", style="yellow", width=8)
        detail_table.add_column("Details", style="dim", width=40)

        for test in results["tests"]:
            if test["status"] == "SECURE":
                status_style = "green"
                status_text = "✅ SECURE"
            elif test["status"] == "VULNERABLE":
                status_style = "red"
                status_text = "🚨 VULNERABLE"
            else:
                status_style = "yellow"
                status_text = f"⚠️  {test['status']}"

            detail_table.add_row(
                test["test_name"],
                f"[{status_style}]{status_text}[/{status_style}]",
                str(test["response_status"]) if test["response_status"] else "N/A",
                test["vulnerability_details"][:40] if test["vulnerability_details"] else "Request properly rejected",
            )

        console.print(detail_table)

    # Final security assessment and recommendations
    if vulnerable_tests == 0:
        console.print(
            Panel(
                """
[bold green]🛡️  SECURITY ASSESSMENT: PASSED[/bold green]

✅ All unauthorized requests were properly rejected
✅ No authentication bypass vulnerabilities detected
✅ JWT token validation is working correctly
✅ Injection attack prevention is effective
✅ Privilege escalation attempts were blocked

[green]The authentication system appears to be secure against common attack vectors.[/green]

[dim]Note: This assessment covers common authentication vulnerabilities. Consider professional
penetration testing for comprehensive security evaluation.[/dim]
                """,
                title="🔒 Security Assessment Complete",
                border_style="green",
            )
        )
    else:
        console.print(
            Panel(
                f"""
[bold red]🚨 SECURITY ASSESSMENT: FAILED[/bold red]

❌ {vulnerable_tests} critical security vulnerabilit{"ies" if vulnerable_tests != 1 else "y"} detected
❌ Unauthorized requests are being accepted
❌ Authentication bypass is possible
❌ System is vulnerable to unauthorized access

[bold red]IMMEDIATE ACTION REQUIRED:[/bold red]
• Stop using this system until vulnerabilities are fixed
• Review authentication and authorization logic
• Contact security team for emergency response
• Consider taking the system offline until secure

[red]This system is NOT SECURE and should not be used in production.[/red]
                """,
                title="⚠️  Critical Security Issues Detected",
                border_style="red",
            )
        )
