"""
Make HTTP requests with comprehensive authentication, session management, and metrics.
Supports all major authentication types and enterprise patterns.

Environment Variable Support:
1. Authentication tokens:
   - Uses auth_env_var parameter to read tokens from environment (e.g., GITHUB_TOKEN, GITLAB_TOKEN)
   - Example: http_request(method="GET", url="...", auth_type="token", auth_env_var="GITHUB_TOKEN")
   - Supported variables: GITHUB_TOKEN, GITLAB_TOKEN, SLACK_BOT_TOKEN, AWS_ACCESS_KEY_ID, etc.
2. AWS credentials:
   - Reads AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN, AWS_REGION automatically
   - Example: http_request(method="GET", url="...", auth_type="aws_sig_v4", aws_auth={"service": "s3"})
Use the environment tool (agent.tool.environment) to view available environment variables:
- List all: environment(action="list")
- Get specific: environment(action="get", name="GITHUB_TOKEN")
- Set new: environment(action="set", name="CUSTOM_TOKEN", value="your-token")
"""

import base64
import collections
import datetime
import http.cookiejar
import json
import os
import time
from typing import Any, Dict, Optional, Union
from urllib.parse import urlparse

import markdownify
import readabilipy.simple_json
import requests
from aws_requests_auth.aws_auth import AWSRequestsAuth
from requests.adapters import HTTPAdapter
from rich import box
from rich.panel import Panel
from rich.syntax import Syntax
from rich.table import Table
from rich.text import Text
from strands.types.tools import (
    ToolResult,
    ToolUse,
)
from urllib3 import Retry

from strands_tools.utils import console_util
from strands_tools.utils.user_input import get_user_input

TOOL_SPEC = {
    "name": "http_request",
    "description": (
        "Make HTTP requests to any API with comprehensive authentication including Bearer tokens, Basic auth, "
        "JWT, AWS SigV4, Digest auth, and enterprise authentication patterns. Automatically reads tokens from "
        "environment variables (GITHUB_TOKEN, GITLAB_TOKEN, AWS credentials, etc.) when auth_env_var is specified. "
        "Use environment(action='list') to view available variables. Includes session management, metrics, "
        "streaming support, cookie handling, redirect control, and optional HTML to markdown conversion."
    ),
    "inputSchema": {
        "json": {
            "type": "object",
            "properties": {
                "method": {
                    "type": "string",
                    "description": "HTTP method (GET, POST, PUT, DELETE, etc.)",
                },
                "url": {
                    "type": "string",
                    "description": "The URL to send the request to",
                },
                "auth_type": {
                    "type": "string",
                    "enum": [
                        "Bearer",
                        "token",
                        "basic",
                        "digest",
                        "jwt",
                        "aws_sig_v4",
                        "kerberos",
                        "custom",
                        "api_key",
                    ],
                    "description": "Authentication type to use",
                },
                "auth_token": {
                    "type": "string",
                    "description": "Authentication token (if not provided, will check environment variables)",
                },
                "auth_env_var": {
                    "type": "string",
                    "description": "Name of environment variable containing the auth token",
                },
                "headers": {
                    "type": "object",
                    "description": "HTTP headers as key-value pairs",
                },
                "body": {
                    "type": "string",
                    "description": "Request body (for POST, PUT, etc.)",
                },
                "verify_ssl": {
                    "type": "boolean",
                    "description": "Whether to verify SSL certificates",
                },
                "cookie": {
                    "type": "string",
                    "description": "Path to cookie file to use for the request",
                },
                "cookie_jar": {
                    "type": "string",
                    "description": "Path to cookie jar file to save cookies to",
                },
                "session_config": {
                    "type": "object",
                    "description": "Session configuration (cookies, keep-alive, etc)",
                    "properties": {
                        "keep_alive": {"type": "boolean"},
                        "max_retries": {"type": "integer"},
                        "pool_size": {"type": "integer"},
                        "cookie_persistence": {"type": "boolean"},
                    },
                },
                "metrics": {
                    "type": "boolean",
                    "description": "Whether to collect request metrics",
                },
                "streaming": {
                    "type": "boolean",
                    "description": "Enable streaming response handling",
                },
                "allow_redirects": {
                    "type": "boolean",
                    "description": "Whether to follow redirects (default: True)",
                },
                "max_redirects": {
                    "type": "integer",
                    "description": "Maximum number of redirects to follow (default: 30)",
                },
                "convert_to_markdown": {
                    "type": "boolean",
                    "description": "Convert HTML responses to markdown format (default: False).",
                },
                "aws_auth": {
                    "type": "object",
                    "description": "AWS auth configuration for SigV4",
                    "properties": {
                        "service": {"type": "string"},
                        "region": {"type": "string"},
                        "access_key": {"type": "string"},
                        "secret_key": {"type": "string"},
                        "session_token": {"type": "string"},
                        "refresh_credentials": {"type": "boolean"},
                    },
                },
                "basic_auth": {
                    "type": "object",
                    "description": "Basic auth credentials",
                    "properties": {
                        "username": {"type": "string"},
                        "password": {"type": "string"},
                    },
                    "required": ["username", "password"],
                },
                "digest_auth": {
                    "type": "object",
                    "description": "Digest auth credentials",
                    "properties": {
                        "username": {"type": "string"},
                        "password": {"type": "string"},
                        "realm": {"type": "string"},
                    },
                },
                "jwt_config": {
                    "type": "object",
                    "description": "JWT configuration",
                    "properties": {
                        "secret": {"type": "string"},
                        "algorithm": {"type": "string"},
                        "expiry": {"type": "integer"},
                    },
                },
            },
            "required": ["method", "url"],
        }
    },
}

# Session cache keyed by domain
SESSION_CACHE = {}

# Metrics storage
REQUEST_METRICS = collections.defaultdict(list)


def extract_content_from_html(html: str) -> str:
    """Extract and convert HTML content to Markdown format.

    Args:
        html: Raw HTML content to process

    Returns:
        Simplified markdown version of the content, or original HTML if conversion fails
    """
    try:
        ret = readabilipy.simple_json.simple_json_from_html_string(html, use_readability=True)
        if not ret.get("content"):
            return html

        content = markdownify.markdownify(
            ret["content"],
            heading_style=markdownify.ATX,
        )
        return content
    except Exception:
        # If conversion fails, return original HTML
        return html


def create_session(config: Dict[str, Any]) -> requests.Session:
    """Create and configure a requests Session object."""
    session = requests.Session()

    if config.get("keep_alive", True):
        adapter = HTTPAdapter(
            pool_connections=config.get("pool_size", 10),
            pool_maxsize=config.get("pool_size", 10),
            max_retries=Retry(
                total=config.get("max_retries", 3),
                backoff_factor=0.5,
                status_forcelist=[500, 502, 503, 504],
            ),
        )
        session.mount("http://", adapter)
        session.mount("https://", adapter)

    if not config.get("cookie_persistence", True):
        session.cookies.clear()

    return session


def get_cached_session(url: str, config: Dict[str, Any]) -> requests.Session:
    """Get or create a cached session for the domain."""
    domain = urlparse(url).netloc
    if domain not in SESSION_CACHE:
        SESSION_CACHE[domain] = create_session(config)
    return SESSION_CACHE[domain]


def process_metrics(start_time: float, response: requests.Response) -> Dict[str, Any]:
    """Process and store request metrics."""
    end_time = time.time()
    metrics = {
        "duration": round(end_time - start_time, 3),
        "status_code": response.status_code,
        "bytes_sent": (len(response.request.body) if response.request and response.request.body is not None else 0),
        "bytes_received": len(response.content),
        "timestamp": datetime.datetime.now().isoformat(),
    }
    REQUEST_METRICS[urlparse(response.url).netloc].append(metrics)
    return metrics


def handle_basic_auth(username: str, password: str) -> Dict[str, str]:
    """Process Basic authentication."""
    credentials = base64.b64encode(f"{username}:{password}".encode()).decode()
    return {"Authorization": f"Basic {credentials}"}


def handle_digest_auth(config: Dict[str, Any], method: str, url: str) -> requests.auth.HTTPDigestAuth:
    """Set up Digest authentication."""
    return requests.auth.HTTPDigestAuth(config["username"], config["password"])


def get_aws_credentials() -> tuple:
    """Get AWS credentials from boto3 with proper credential chain."""
    import boto3

    # Create a boto3 session to ensure we're using the same credential chain
    session = boto3.Session()
    credentials = session.get_credentials()

    if not credentials:
        raise ValueError("No AWS credentials found in the credential chain")

    frozen = credentials.get_frozen_credentials()
    return frozen, session.region_name


def handle_aws_sigv4(config: Dict[str, Any], url: str) -> AWSRequestsAuth:
    """
    Configure AWS SigV4 authentication using boto3's credential chain.
    """
    try:
        # Get credentials using boto3's credential chain
        credentials, default_region = get_aws_credentials()

        # Get service from config (required)
        service = config["service"]

        # Get region from config or use default
        region = config.get("region") or default_region

        if not region:
            raise ValueError("AWS region not found in config or environment")

        parsed = urlparse(url)
        auth = AWSRequestsAuth(
            aws_access_key=credentials.access_key,
            aws_secret_access_key=credentials.secret_key,
            aws_host=parsed.netloc,
            aws_region=region,
            aws_service=service,
            aws_token=credentials.token,  # Add session token directly
        )

        return auth

    except Exception as e:
        raise ValueError(f"AWS authentication error: {str(e)}") from e


def handle_jwt(config: Dict[str, Any]) -> Dict[str, str]:
    """Process JWT authentication."""
    try:
        import jwt  # Imported here to avoid global dependency
    except ImportError:
        raise ImportError(
            "ImportError: PyJWT package is required for JWT authentication. Install with: pip install PyJWT"
        ) from None

    # Create expiration time using datetime module properly
    expiry_time = datetime.datetime.now(datetime.timezone.utc) + datetime.timedelta(seconds=config["expiry"])
    token = jwt.encode(
        {"exp": expiry_time},
        config["secret"],
        algorithm=config["algorithm"],
    )

    # Convert token to string based on type
    token_str = token.decode("utf-8") if hasattr(token, "decode") else str(token)

    return {"Authorization": f"Bearer {token_str}"}


def format_json_response(content: str) -> Union[str, Syntax]:
    """Format JSON response with syntax highlighting if valid JSON."""
    try:
        parsed = json.loads(content)
        formatted = json.dumps(parsed, indent=2)
        return Syntax(formatted, "json", theme="monokai", line_numbers=False)
    except BaseException:
        return content


def format_headers_table(headers: Dict) -> Table:
    """Format headers as a rich table."""
    table = Table(title="Response Headers", show_header=True, box=box.ROUNDED)
    table.add_column("Header", style="cyan")
    table.add_column("Value", style="green")

    for key, value in headers.items():
        # Truncate very long header values
        if isinstance(value, str) and len(value) > 100:
            value = f"{value[:100]}..."
        table.add_row(key, str(value))

    return table


def process_auth_headers(headers: Dict[str, Any], tool_input: Dict[str, Any]) -> Dict[str, Any]:
    """
    Process authentication headers based on input parameters.

    Supports multiple authentication methods:
    1. Environment variables: Uses auth_env_var to read tokens
    2. Direct token: Uses auth_token parameter

    Special handling for different APIs:
    - GitHub: Uses "token" prefix (auth_type="token")
    - GitLab: Uses "Bearer" prefix (auth_type="Bearer")
    - AWS: Uses SigV4 signing (auth_type="aws_sig_v4")

    Examples:
        # GitHub API with environment variable
        process_auth_headers({}, {"auth_type": "token", "auth_env_var": "GITHUB_TOKEN"})

        # GitLab API with environment variable
        process_auth_headers({}, {"auth_type": "Bearer", "auth_env_var": "GITLAB_TOKEN"})
    """
    headers = headers or {}

    # Get auth token from input or environment
    auth_token = tool_input.get("auth_token")
    if not auth_token and "auth_env_var" in tool_input:
        env_var_name = tool_input["auth_env_var"]
        auth_token = os.getenv(env_var_name)
        if not auth_token:
            raise ValueError(
                f"Environment variable '{env_var_name}' not found or empty. "
                f"Use environment(action='list') to see available variables."
            )

    auth_type = tool_input.get("auth_type")

    if auth_token:
        # Handle other auth types
        if auth_type == "Bearer":
            headers["Authorization"] = f"Bearer {auth_token}"
        elif auth_type == "token":
            # GitHub API uses 'token' prefix
            headers["Authorization"] = f"token {auth_token}"

            # Special case for GitHub API to add proper Accept header if not present
            if "Accept" not in headers and "github" in tool_input.get("url", "").lower():
                headers["Accept"] = "application/vnd.github.v3+json"

        elif auth_type == "custom":
            headers["Authorization"] = auth_token
        elif auth_type == "api_key":
            headers["X-API-Key"] = auth_token

    return headers


def stream_response(response: requests.Response) -> str:
    """Handle streaming response processing."""
    chunks = []
    for chunk in response.iter_content(chunk_size=8192):
        if chunk:
            chunks.append(chunk)
    return b"".join(chunks).decode()


def format_request_preview(method: str, url: str, headers: Dict, body: Optional[str] = None) -> Panel:
    """Format request details for preview."""
    table = Table(show_header=False, box=box.SIMPLE)
    table.add_column("Field", style="cyan")
    table.add_column("Value", style="white")

    table.add_row("Method", method)
    table.add_row("URL", url)

    # Add headers (hide sensitive values)
    headers_str = {}
    for key, value in headers.items():
        if key.lower() in ["authorization", "x-api-key", "cookie"]:
            # Show first 4 and last 4 chars if long enough, otherwise mask completely
            if isinstance(value, str) and len(value) > 12:
                headers_str[key] = f"{value[:4]}...{value[-4:]}"
            else:
                headers_str[key] = "********"
        else:
            headers_str[key] = value

    table.add_row("Headers", str(headers_str))

    if body:
        # Try to format body as JSON if it's valid
        try:
            json_body = json.loads(body)
            body = json.dumps(json_body, indent=2)
            body_preview = body[:200] + "..." if len(body) > 200 else body
            table.add_row("Body", f"(JSON) {body_preview}")
        except BaseException:
            body_preview = body[:200] + "..." if len(body) > 200 else body
            table.add_row("Body", body_preview)

    return Panel(
        table,
        title=f"[bold blue]🚀 HTTP Request Preview: {method} {urlparse(url).path}",
        border_style="blue",
        box=box.ROUNDED,
    )


def format_response_preview(
    response: requests.Response, content: str, metrics: Optional[Dict[Any, Any]] = None
) -> Panel:
    """Format response for preview."""
    status_code = response.status_code if response and hasattr(response, "status_code") else 0
    status_style = "green" if 200 <= status_code < 400 else "red"  # type: ignore

    # Main content panel
    main_table = Table(show_header=False, box=box.SIMPLE)
    main_table.add_column("Field", style="cyan")
    main_table.add_column("Value")

    # Status code with color
    main_table.add_row("Status", Text(f"{response.status_code} {response.reason}", style=status_style))

    # URL
    main_table.add_row("URL", response.url)

    # Content type
    content_type = response.headers.get("Content-Type", "unknown")
    main_table.add_row("Content-Type", content_type)

    # Size
    size_bytes = len(response.content)
    size_display = f"{size_bytes:,} bytes"
    if size_bytes > 1024:
        size_display += f" ({size_bytes / 1024:.1f} KB)"
    main_table.add_row("Size", size_display)

    # Timing if metrics available
    if metrics and "duration" in metrics:
        main_table.add_row("Duration", f"{metrics['duration']:.3f} seconds")

    # Format and preview content based on content type
    if "application/json" in content_type:
        try:
            # Format JSON for display
            json_obj = json.loads(content)
            # Create syntax highlighted JSON
            Syntax(
                json.dumps(json_obj, indent=2),
                "json",
                theme="monokai",
                line_numbers=False,
            )
        except BaseException:
            # Not valid JSON, show as text
            Text(content[:500] + "..." if len(content) > 500 else content)
    elif "text/html" in content_type:
        Syntax(
            content[:500] + "..." if len(content) > 500 else content,
            "html",
            theme="monokai",
            line_numbers=False,
        )
    else:
        # Default text preview
        Text(content[:500] + "..." if len(content) > 500 else content)

    # Combine into main panel
    status_emoji = "✅" if 200 <= status_code < 400 else "❌"  # type: ignore
    reason = response.reason if response and hasattr(response, "reason") else ""
    return Panel(
        Panel(main_table, border_style="blue", box=box.SIMPLE),
        title=f"[bold {status_style}]{status_emoji} HTTP Response: {status_code} {reason}",
        border_style=status_style,
        box=box.ROUNDED,
    )


def http_request(tool: ToolUse, **kwargs: Any) -> ToolResult:
    """
    Execute HTTP request with comprehensive authentication and features.

    Common API Examples:

    1. GitHub API (uses "token" auth_type):
        ```python
        http_request(
            method="GET",
            url="https://api.github.com/user",
            auth_type="token",
            auth_env_var="GITHUB_TOKEN",
        )
        ```

    2. GitLab API (uses "Bearer" auth_type):
        ```python
        http_request(
            method="GET",
            url="https://gitlab.com/api/v4/user",
            auth_type="Bearer",
            auth_env_var="GITLAB_TOKEN",
        )
        ```

    3. AWS S3 (uses "aws_sig_v4" auth_type):
        ```python
        http_request(
            method="GET",
            url="https://s3.amazonaws.com/my-bucket",
            auth_type="aws_sig_v4",
            aws_auth={"service": "s3"},
        )
        ```

    4. Using cookies from file and saving to cookie jar:
        ```python
        http_request(
            method="GET",
            url="https://internal-site.amazon.com",
            cookie="~/.midway/cookie",
            cookie_jar="~/.midway/cookie.updated",
        )
        ```

    5. Control redirect behavior:
        ```python
        http_request(
            method="GET",
            url="https://example.com/redirect",
            allow_redirects=True,  # Default behavior
            max_redirects=5,  # Limit number of redirects to follow
        )
        ```

    6. Convert HTML responses to markdown:
        ```python
        http_request(
            method="GET",
            url="https://example.com/article",
            convert_to_markdown=True,  # Converts HTML content to readable markdown
        )
        ```

    Environment Variables:
    - Authentication tokens are read from environment when auth_env_var is specified
    - AWS credentials are automatically loaded from environment variables or credentials file
    - Use environment(action='list') to view all available environment variables
    """
    console = console_util.create()

    try:
        # Extract input from tool use object or use directly if already a dict
        tool_input = {}
        tool_use_id = "default_id"

        if isinstance(tool, dict):
            if "input" in tool:
                tool_input = tool["input"]
                tool_use_id = tool.get("toolUseId", "default_id")
            # No else here - tool_input has already been initialized

        method = tool_input["method"]
        url = tool_input["url"]
        headers = process_auth_headers(tool_input.get("headers", {}), tool_input)
        body = tool_input.get("body")
        verify = tool_input.get("verify_ssl", True)
        cookie = tool_input.get("cookie")
        cookie_jar = tool_input.get("cookie_jar")

        # Preview request before execution
        preview_panel = format_request_preview(method, url, headers, body)
        console.print(preview_panel)

        # Check if we're in development mode
        strands_dev = os.environ.get("BYPASS_TOOL_CONSENT", "").lower() == "true"

        # For modifying operations (non-GET requests), show confirmation dialog unless in BYPASS_TOOL_CONSENT mode
        modifying_methods = {"POST", "PUT", "PATCH", "DELETE"}
        needs_confirmation = method.upper() in modifying_methods and not strands_dev

        if needs_confirmation:
            # Show warning for potentially modifying requests
            target_url = urlparse(url)
            warning_panel = Panel(
                Text.assemble(
                    ("⚠️ Warning: ", "bold red"),
                    (f"{method.upper()} request may modify data at ", "yellow"),
                    (f"{target_url.netloc}{target_url.path}", "bold yellow"),
                ),
                title="[bold red]Modifying Request Confirmation",
                border_style="red",
                box=box.DOUBLE,
                expand=False,
                padding=(1, 1),
            )
            console.print(warning_panel)

            # If body exists, show preview
            if body:
                try:
                    # Try to format as JSON
                    json_body = json.loads(body)
                    body_preview = json.dumps(json_body, indent=2)
                    console.print(
                        Panel(
                            Syntax(body_preview, "json", theme="monokai"),
                            title="[bold blue]Request Body Preview",
                            border_style="blue",
                            box=box.ROUNDED,
                        )
                    )
                except BaseException:
                    # Not JSON, show as plain text
                    console.print(
                        Panel(
                            Text(body[:500] + "..." if len(body) > 500 else body),
                            title="[bold blue]Request Body Preview",
                            border_style="blue",
                            box=box.ROUNDED,
                        )
                    )

            # Get user confirmation
            user_input = get_user_input(
                f"<yellow><bold>Do you want to proceed with this {method.upper()} request?</bold> [y/*]</yellow>"
            )
            if user_input.lower().strip() != "y":
                cancellation_reason = (
                    user_input
                    if user_input.strip() != "n"
                    else get_user_input("Please provide a reason for cancellation:")
                )
                error_message = f"HTTP request cancelled by the user. Reason: {cancellation_reason}"
                error_panel = Panel(
                    Text(error_message, style="bold red"),
                    title="[bold red]Request Cancelled",
                    border_style="red",
                    box=box.HEAVY,
                    expand=False,
                )
                console.print(error_panel)
                # Return error status for cancellation to ensure test passes
                return {
                    "toolUseId": tool_use_id,
                    "status": "error",
                    "content": [{"text": error_message}],
                }

        # Session handling
        session_config = tool_input.get("session_config", {})
        session = get_cached_session(url, session_config)

        # Authentication processing
        auth: Optional[Union[requests.auth.HTTPDigestAuth, AWSRequestsAuth]] = None
        if "auth_type" in tool_input:
            auth_type = tool_input["auth_type"]

            if auth_type == "digest":
                auth = handle_digest_auth(tool_input["digest_auth"], method, url)
            elif auth_type == "aws_sig_v4":
                auth = handle_aws_sigv4(tool_input["aws_auth"], url)
            elif auth_type == "basic":
                if "basic_auth" not in tool_input:
                    raise ValueError("basic_auth configuration required for basic authentication")
                basic_config = tool_input["basic_auth"]
                if "username" not in basic_config or "password" not in basic_config:
                    raise ValueError("username and password required for basic authentication")
                headers.update(handle_basic_auth(basic_config["username"], basic_config["password"]))
            elif auth_type == "jwt":
                headers.update(handle_jwt(tool_input["jwt_config"]))

        # Show request confirmation message
        console.print(Text("Sending request...", style="blue"))

        # Prepare request
        request_kwargs = {
            "method": method,
            "url": url,
            "headers": headers,
            "verify": verify,
            "auth": auth,
            "allow_redirects": tool_input.get("allow_redirects", True),
        }

        # Set max_redirects if specified
        if "max_redirects" in tool_input:
            max_redirects = tool_input["max_redirects"]
            if max_redirects is not None and hasattr(session, "max_redirects"):
                session.max_redirects = max_redirects

        # Handle cookies
        if cookie:
            cookie_path = os.path.expanduser(cookie)
            if os.path.exists(cookie_path):
                cookies = http.cookiejar.MozillaCookieJar()
                try:
                    # Try Mozilla format first
                    cookies.load(cookie_path, ignore_discard=True, ignore_expires=True)
                    session.cookies.update(cookies)
                except Exception:
                    try:
                        # Try Netscape format (curl style)
                        with open(cookie_path, "r") as f:
                            for line in f:
                                line = line.strip()
                                if line and not line.startswith("#"):
                                    parts = line.split("\t")
                                    if len(parts) >= 7:  # Standard Netscape format
                                        (
                                            domain,
                                            flag,
                                            path,
                                            secure,
                                            expires,
                                            name,
                                            value,
                                        ) = parts
                                        session.cookies.set(name, value, domain=domain, path=path)
                    except Exception as e2:
                        console.print(
                            Text(
                                f"Failed to load cookies from {cookie}: {str(e2)}",
                                style="red",
                            )
                        )
                console.print(Text(f"Using cookies from {cookie}", style="blue"))
            else:
                console.print(Text(f"Warning: Cookie file {cookie} not found", style="yellow"))

        if body:
            request_kwargs["data"] = body

        # Execute request with metrics
        start_time = time.time()
        response = session.request(**request_kwargs)

        # Save cookies to cookie jar if specified
        if cookie_jar:
            cookie_jar_path = os.path.expanduser(cookie_jar)
            # Ensure directory exists
            cookie_jar_dir = os.path.dirname(cookie_jar_path)
            if cookie_jar_dir and not os.path.exists(cookie_jar_dir):
                os.makedirs(cookie_jar_dir, exist_ok=True)

            # Save cookies in Netscape format compatible with curl
            with open(cookie_jar_path, "w") as f:
                f.write("# Netscape HTTP Cookie File\n")
                f.write("# https://curl.se/docs/http-cookies.html\n")
                f.write("# This file was generated by Strands http_request tool\n\n")

                for cookie in session.cookies:
                    # Format is: domain flag path secure expires name value
                    secure = "TRUE" if cookie.secure else "FALSE"
                    httponly = "TRUE" if cookie.has_nonstandard_attr("httponly") else "FALSE"
                    expires = str(int(cookie.expires)) if hasattr(cookie, "expires") and cookie.expires else "0"
                    f.write(
                        f"{cookie.domain}\t{httponly}\t{cookie.path}\t{secure}\t{expires}\t{cookie.name}\t{cookie.value}\n"
                    )

            console.print(Text(f"Cookies saved to {cookie_jar}", style="blue"))

        # Process metrics if enabled
        metrics = None
        if tool_input.get("metrics", False):
            metrics = process_metrics(start_time, response)

        # Handle streaming responses
        if tool_input.get("streaming", False):
            content = stream_response(response)
        else:
            content = response.text

        # Convert HTML to markdown if requested
        convert_to_markdown = tool_input.get("convert_to_markdown", False)
        if convert_to_markdown:
            content_type = response.headers.get("content-type", "")
            is_html_content = (
                "text/html" in content_type.lower()
                or "<html" in content[:100].lower()
                or "<!doctype html" in content[:100].lower()
            )

            if is_html_content:
                original_content = content
                content = extract_content_from_html(content)

                # Add a note if conversion was successful
                if content != original_content:
                    console.print(Text("✓ Converted HTML content to markdown", style="green"))

        # Format and display the response
        response_panel = format_response_preview(response, content, metrics if metrics is not None else None)
        console.print(response_panel)

        # Show redirect information if redirects were followed
        if response.history:
            redirect_count = len(response.history)
            redirect_chain = " -> ".join([str(r.status_code) for r in response.history] + [str(response.status_code)])
            redirect_info = Panel(
                Text.assemble(
                    (f"Followed {redirect_count} redirect(s): ", "yellow"),
                    (redirect_chain, "cyan"),
                ),
                title="[bold blue]Redirect Information",
                border_style="blue",
                box=box.ROUNDED,
                expand=False,
                padding=(1, 1),
            )
            console.print(redirect_info)

        # Show headers in a separate table if response was successful
        if 200 <= response.status_code < 300:
            console.print(format_headers_table(dict(response.headers)))

        # Format response content for output
        result_text = []
        result_text.append(f"Status Code: {response.status_code}")

        # Add redirect information if any redirects were followed
        if response.history:
            redirect_count = len(response.history)
            redirect_chain = " -> ".join([str(r.status_code) for r in response.history] + [str(response.status_code)])
            result_text.append(f"Redirects: {redirect_count} redirects followed ({redirect_chain})")

        # Add minimal headers to text response
        important_headers = ["Content-Type", "Content-Length", "Date", "Server"]
        headers_text = {k: v for k, v in response.headers.items() if k in important_headers}
        result_text.append(f"Headers: {headers_text}")

        # Add body to text response
        result_text.append(f"Body: {content}")

        # Add metrics if available
        if metrics:
            result_text.append(f"Metrics: {metrics}")

        return {
            "toolUseId": tool_use_id,
            "status": "success",
            "content": [{"text": text} for text in result_text],
        }

    except Exception as e:
        error_panel = Panel(
            Text(str(e), style="red"),
            title="❌ HTTP Request Error",
            border_style="red",
            box=box.ROUNDED,
        )
        console.print(error_panel)

        # If the error appears to be related to authentication, show a suggestion
        error_str = str(e).lower()
        suggestion = ""
        if "auth" in error_str or "token" in error_str or "credential" in error_str or "unauthorized" in error_str:
            suggestion = (
                "\n\nSuggestion: Check your authentication setup. Common solutions:\n"
                "- For GitHub API: Use auth_type='token' with auth_env_var='GITHUB_TOKEN'\n"
                "- For GitLab API: Use auth_type='Bearer' with auth_env_var='GITLAB_TOKEN'\n"
                "- Use environment(action='list') to view available environment variables"
            )

        # Special handling for ImportError to help with test assertions
        error_text = f"Error: {str(e)}{suggestion}"
        if isinstance(e, ImportError):
            error_text = f"ImportError: {str(e)}{suggestion}"

        return {
            "toolUseId": tool_use_id,
            "status": "error",
            "content": [{"text": error_text}],
        }
