# congress_api/features/committee_reports.py
import logging
import re
from typing import Dict, Any, Optional
import httpx
from mcp.server.fastmcp import Context
from ..core.client_handler import make_api_request
from ..core.api_wrapper import safe_congressional_request
from ..core.validators import ParameterValidator
from ..core.exceptions import format_error_response, CommonErrors

# Set up logger
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)

# --- Formatting Functions ---

def format_committee_report_item(report: Dict[str, Any]) -> str:
    """Formats a single committee report item for display in a list."""
    lines = [
        f"**Citation**: {report.get('citation', 'N/A')}",
        f"  **Congress**: {report.get('congress', 'N/A')}",
        f"  **Chamber**: {report.get('chamber', 'N/A')}",
        f"  **Type**: {report.get('type', 'N/A')}",
        f"  **Number**: {report.get('number', 'N/A')}",
        f"  **Part**: {report.get('part', 'N/A')}",
        f"  **Update Date**: {report.get('updateDate', 'N/A')}",
        f"  **URL**: {report.get('url', 'N/A')}"
    ]
    return "\n".join(lines)

def format_committee_report_detail(report: Dict[str, Any]) -> str:
    """Formats detailed information for a single committee report."""
    lines = [
        f"# Committee Report Details",
        f"",
        f"**Title**: {report.get('title', 'N/A')}",
        f"**Citation**: {report.get('citation', 'N/A')}",
        f"**Congress**: {report.get('congress', 'N/A')}",
        f"**Chamber**: {report.get('chamber', 'N/A')}",
        f"**Report Type**: {report.get('reportType', 'N/A')} ({report.get('type', 'N/A')})",
        f"**Number**: {report.get('number', 'N/A')}",
        f"**Part**: {report.get('part', 'N/A')}",
        f"**Issue Date**: {report.get('issueDate', 'N/A')}",
        f"**Update Date**: {report.get('updateDate', 'N/A')}",
        f"**Is Conference Report**: {'Yes' if report.get('isConferenceReport') else 'No'}",
        f"**Session Number**: {report.get('sessionNumber', 'N/A')}",
    ]
    
    if 'associatedBill' in report and report['associatedBill']:
        lines.append("")
        lines.append("## Associated Bills:")
        for bill in report['associatedBill']:
            lines.append(f"- **{bill.get('type', '')}{bill.get('number', '')}** (Congress {bill.get('congress', '')}) - [View Bill]({bill.get('url', 'N/A')})")
    
    if 'text' in report and report['text'].get('url'):
        lines.append("")
        lines.append(f"## Text Versions")
        lines.append(f"**URL**: {report['text']['url']}")
        lines.append(f"**Count**: {report['text'].get('count', 'N/A')}")
        
    return "\n".join(lines)

def format_committee_report_text_version(text_version_item: Dict[str, Any]) -> str:
    """Formats a single text version format item."""
    lines = []
    for fmt in text_version_item.get('formats', []):
        lines.append(f"**Format**: {fmt.get('type', 'N/A')}")
        lines.append(f"  **URL**: {fmt.get('url', 'N/A')}")
    return "\n".join(lines)

# --- MCP Tools ---

# @require_paid_access
async def get_latest_committee_reports(ctx: Context) -> str:
    """
    Get a list of the most recent committee reports.
    Returns the 10 most recently updated reports by default.
    """
    logger.debug("Fetching latest committee reports")
    
    try:
        # Make defensive API request
        data = await safe_congressional_request("/committee-report", ctx, {})
        
        if not data or 'reports' not in data:
            logger.warning("No committee reports data received from API")
            return format_error_response(CommonErrors.data_not_found("committee reports"))
        
        # Process and clean response - use reports data directly since base endpoint returns 'reports'
        reports_data = data['reports']
        if not reports_data:
            logger.info("No committee reports found")
            return "No committee reports found."
        
        # Apply deduplication and sorting manually since clean_committee_reports_response expects 'committeeReports'
        from congress_api.core.response_utils import CommitteeReportsProcessor
        
        # Deduplicate and sort
        deduplicated_reports = CommitteeReportsProcessor.deduplicate_reports(reports_data)
        sorted_reports = sorted(deduplicated_reports, key=lambda x: x.get('updateDate', ''), reverse=True)
        limited_reports = sorted_reports[:10]  # Limit to 10 most recent
        
        logger.info(f"Found {len(limited_reports)} committee reports")
        
        # Format results
        formatted_reports = []
        for report in limited_reports:
            formatted_reports.append(format_committee_report_item(report))
        
        result = f"# Latest Committee Reports ({len(limited_reports)} found)\n\n"
        result += "\n\n---\n\n".join(formatted_reports)
        
        return result
        
    except Exception as e:
        logger.error(f"Error fetching latest committee reports: {str(e)}")
        return format_error_response(CommonErrors.api_server_error(
            "Failed to fetch latest committee reports",
            message=str(e)
        ))

# @require_paid_access
async def get_committee_reports_by_congress(ctx: Context, congress: int) -> str:
    """
    Get committee reports for a specific Congress.
    
    Args:
        congress: The Congress number (e.g., 117).
    """
    logger.debug(f"Fetching committee reports for Congress {congress}")
    
    # Validate congress parameter
    validation = ParameterValidator.validate_congress_number(congress)
    if not validation.is_valid:
        logger.warning(f"Invalid congress number: {congress}")
        return format_error_response(CommonErrors.invalid_congress_number(congress))
    
    try:
        endpoint = f"/committee-report/{congress}"
        data = await safe_congressional_request(endpoint, ctx, {})
        
        if not data or 'reports' not in data:
            logger.warning(f"No committee reports data received for Congress {congress}")
            return format_error_response(CommonErrors.data_not_found(
                "committee reports", 
                {"congress": congress}
            ))
        
        # Process and clean response - use reports data directly since congress endpoint returns 'reports'
        reports_data = data['reports']
        if not reports_data:
            logger.info(f"No committee reports found for Congress {congress}")
            return format_error_response(CommonErrors.data_not_found(
                "committee reports", 
                {"congress": congress}
            ))
        
        # Apply deduplication and sorting manually since clean_committee_reports_response expects 'committeeReports'
        from congress_api.core.response_utils import CommitteeReportsProcessor
        
        # Deduplicate and sort
        deduplicated_reports = CommitteeReportsProcessor.deduplicate_reports(reports_data)
        sorted_reports = sorted(deduplicated_reports, key=lambda x: x.get('updateDate', ''), reverse=True)
        limited_reports = sorted_reports[:10]  # Limit to 10 most recent
        
        logger.info(f"Found {len(limited_reports)} committee reports for Congress {congress}")
        
        # Format results
        formatted_reports = []
        for report in limited_reports:
            formatted_reports.append(format_committee_report_item(report))
        
        result = f"# Committee Reports for Congress {congress} ({len(limited_reports)} found)\n\n"
        result += "\n\n---\n\n".join(formatted_reports)
        
        return result
        
    except Exception as e:
        logger.error(f"Error fetching committee reports for Congress {congress}: {str(e)}")
        return format_error_response(CommonErrors.api_server_error(
            f"Failed to fetch committee reports for Congress {congress}",
            message=str(e)
        ))

# @require_paid_access
async def get_committee_reports_by_congress_and_type(
    ctx: Context,
    congress: int, 
    report_type: str
) -> str:
    """
    Get committee reports for a specific Congress and report type.
    
    Args:
        congress: The Congress number (e.g., 117).
        report_type: The type of report (e.g., "hrpt", "srpt").
    """
    logger.debug(f"Fetching committee reports for Congress {congress}, type {report_type}")
    
    # Validate congress parameter
    validation = ParameterValidator.validate_congress_number(congress)
    if not validation.is_valid:
        logger.warning(f"Invalid congress number: {congress}")
        return format_error_response(CommonErrors.invalid_congress_number(congress))
    
    # Validate report type
    report_type_validation = ParameterValidator.validate_report_type(report_type)
    if not report_type_validation.is_valid:
        logger.warning(f"Invalid report type: {report_type}")
        return format_error_response(CommonErrors.invalid_parameter(
            "report_type", 
            report_type, 
            report_type_validation.error_message
        ))
    
    try:
        endpoint = f"/committee-report/{congress}/{report_type}"
        data = await safe_congressional_request(endpoint, ctx, {})
        
        if not data or 'reports' not in data:
            logger.warning(f"No committee reports data received for Congress {congress}, type {report_type}")
            return format_error_response(CommonErrors.data_not_found(
                "committee reports", 
                {"congress": congress, "report_type": report_type}
            ))
        
        # Process and clean response - use reports data directly since congress/type endpoint returns 'reports'
        reports_data = data['reports']
        if not reports_data:
            logger.info(f"No committee reports found for Congress {congress}, type {report_type}")
            return format_error_response(CommonErrors.data_not_found(
                "committee reports", 
                {"congress": congress, "report_type": report_type}
            ))
        
        # Apply deduplication and sorting manually since clean_committee_reports_response expects 'committeeReports'
        from congress_api.core.response_utils import CommitteeReportsProcessor
        
        # Deduplicate and sort
        deduplicated_reports = CommitteeReportsProcessor.deduplicate_reports(reports_data)
        sorted_reports = sorted(deduplicated_reports, key=lambda x: x.get('updateDate', ''), reverse=True)
        limited_reports = sorted_reports[:50]  # Limit to 50 most recent
        
        logger.info(f"Found {len(limited_reports)} committee reports for Congress {congress}, type {report_type}")
        
        # Format results
        formatted_reports = []
        for report in limited_reports:
            formatted_reports.append(format_committee_report_item(report))
        
        result = f"# Committee Reports for Congress {congress}, Type {report_type} ({len(limited_reports)} found)\n\n"
        result += "\n\n---\n\n".join(formatted_reports)
        
        return result
        
    except Exception as e:
        logger.error(f"Error fetching committee reports for Congress {congress}, type {report_type}: {str(e)}")
        return format_error_response(CommonErrors.api_server_error(
            f"Failed to fetch committee reports for Congress {congress}, type {report_type}",
            message=str(e)
        ))

# @require_paid_access
async def get_committee_report_details(
    ctx: Context,
    congress: int,
    report_type: str,
    report_number: int
) -> str:
    """
    Get detailed information for a specific committee report.
    
    Args:
        congress: The Congress number (e.g., 117).
        report_type: The type of report (e.g., "hrpt", "srpt", "erpt").
        report_number: The report number.
    """
    logger.debug(f"Fetching details for committee report {congress}/{report_type}/{report_number}")
    
    # Validate congress parameter
    validation = ParameterValidator.validate_congress_number(congress)
    if not validation.is_valid:
        logger.warning(f"Invalid congress number: {congress}")
        return format_error_response(CommonErrors.invalid_congress_number(congress))
    
    # Validate report type
    report_type_validation = ParameterValidator.validate_report_type(report_type)
    if not report_type_validation.is_valid:
        logger.warning(f"Invalid report type: {report_type}")
        return format_error_response(CommonErrors.invalid_parameter(
            "report_type", 
            report_type, 
            report_type_validation.error_message
        ))
    
    # Validate report number
    report_number_validation = ParameterValidator.validate_report_number(report_number)
    if not report_number_validation.is_valid:
        logger.warning(f"Invalid report number: {report_number}")
        return format_error_response(CommonErrors.invalid_parameter(
            "report_number", 
            report_number, 
            report_number_validation.error_message
        ))
    
    try:
        endpoint = f"/committee-report/{congress}/{report_type}/{report_number}"
        data = await safe_congressional_request(endpoint, ctx, {})
        
        if not data or 'committeeReports' not in data:
            logger.warning(f"No committee report data received for {congress}/{report_type}/{report_number}")
            return format_error_response(CommonErrors.data_not_found(
                "committee report", 
                {"congress": congress, "report_type": report_type, "report_number": report_number}
            ))
        
        reports = data['committeeReports']
        if not reports:
            logger.warning(f"Empty committee reports list for {congress}/{report_type}/{report_number}")
            return format_error_response(CommonErrors.data_not_found(
                "committee report", 
                {"congress": congress, "report_type": report_type, "report_number": report_number}
            ))
        
        report_item = reports[0]  # Get the first (and likely only) report
        
        logger.info(f"Successfully retrieved committee report details for {congress}/{report_type}/{report_number}")
        
        return format_committee_report_detail(report_item)
        
    except Exception as e:
        logger.error(f"Error fetching committee report details for {congress}/{report_type}/{report_number}: {str(e)}")
        return format_error_response(CommonErrors.api_server_error(
            f"Failed to fetch committee report details for {congress}/{report_type}/{report_number}",
            message=str(e)
        ))

# @require_paid_access
async def get_committee_report_text_versions(
    ctx: Context,
    congress: int, 
    report_type: str, 
    report_number: int
) -> str:
    """
    Get text versions for a specific committee report.
    
    Args:
        congress: The Congress number (e.g., 117).
        report_type: The type of report (e.g., "hrpt").
        report_number: The report number.
    """
    logger.debug(f"Fetching text versions for committee report {congress}/{report_type}/{report_number}")
    
    # Validate congress parameter
    validation = ParameterValidator.validate_congress_number(congress)
    if not validation.is_valid:
        logger.warning(f"Invalid congress number: {congress}")
        return format_error_response(CommonErrors.invalid_congress_number(congress))
    
    # Validate report type
    report_type_validation = ParameterValidator.validate_report_type(report_type)
    if not report_type_validation.is_valid:
        logger.warning(f"Invalid report type: {report_type}")
        return format_error_response(CommonErrors.invalid_parameter(
            "report_type", 
            report_type, 
            report_type_validation.error_message
        ))
    
    # Validate report number
    report_number_validation = ParameterValidator.validate_report_number(report_number)
    if not report_number_validation.is_valid:
        logger.warning(f"Invalid report number: {report_number}")
        return format_error_response(CommonErrors.invalid_parameter(
            "report_number", 
            report_number, 
            report_number_validation.error_message
        ))
    
    try:
        endpoint = f"/committee-report/{congress}/{report_type}/{report_number}/text"
        data = await safe_congressional_request(endpoint, ctx, {})
        
        if not data or 'text' not in data:
            logger.warning(f"No text versions data received for committee report {congress}/{report_type}/{report_number}")
            return format_error_response(CommonErrors.data_not_found(
                "committee report text versions", 
                {"congress": congress, "report_type": report_type, "report_number": report_number}
            ))
        
        text_versions = data['text']
        
        if not text_versions:
            logger.info(f"No text versions found for committee report {congress}/{report_type}/{report_number}")
            return f"No text versions found for committee report {congress}/{report_type}/{report_number}."
        
        logger.info(f"Found {len(text_versions)} text versions for committee report {congress}/{report_type}/{report_number}")
        
        # Format results
        formatted_versions = []
        for version in text_versions:
            formatted_versions.append(format_committee_report_text_version(version))
        
        result = f"# Text Versions for Committee Report {congress}/{report_type}/{report_number} ({len(text_versions)} found)\n\n"
        result += "\n\n---\n\n".join(formatted_versions)
        
        return result
        
    except Exception as e:
        logger.error(f"Error fetching text versions for committee report {congress}/{report_type}/{report_number}: {str(e)}")
        return format_error_response(CommonErrors.api_server_error(
            f"Failed to fetch text versions for committee report {congress}/{report_type}/{report_number}",
            message=str(e)
        ))

# @require_paid_access
async def search_committee_reports(
    ctx: Context,
    conference: Optional[str] = None,
    offset: Optional[int] = None,
    limit: Optional[int] = None,
    fromDateTime: Optional[str] = None,
    toDateTime: Optional[str] = None
) -> str:
    """
    Search for committee reports based on various criteria.

    Args:
        conference: Filter by conference reports (true or false).
        offset: The starting record for pagination.
        limit: The number of records to return (max 250).
        fromDateTime: Start date for filtering by update date (YYYY-MM-DDT00:00:00Z).
        toDateTime: End date for filtering by update date (YYYY-MM-DDT00:00:00Z).
    """
    logger.debug(f"Searching committee reports with criteria: conference={conference}, offset={offset}, limit={limit}")
    
    # Validate parameters
    params = {}
    
    if conference is not None:
        conference_validation = ParameterValidator.validate_conference_filter(conference)
        if not conference_validation.is_valid:
            logger.warning(f"Invalid conference parameter: {conference}")
            return format_error_response(CommonErrors.invalid_parameter(
                "conference", 
                conference, 
                conference_validation.error_message
            ))
        params['conference'] = conference
    
    if offset is not None:
        offset_validation = ParameterValidator.validate_offset(offset)
        if not offset_validation.is_valid:
            logger.warning(f"Invalid offset parameter: {offset}")
            return format_error_response(CommonErrors.invalid_parameter(
                "offset", 
                offset, 
                offset_validation.error_message
            ))
        params['offset'] = offset
    
    if limit is not None:
        limit_validation = ParameterValidator.validate_limit_range(limit, max_limit=250)
        if not limit_validation.is_valid:
            logger.warning(f"Invalid limit parameter: {limit}")
            return format_error_response(CommonErrors.invalid_parameter(
                "limit", 
                limit, 
                limit_validation.error_message
            ))
        params['limit'] = limit
    
    if fromDateTime is not None:
        from_date_validation = ParameterValidator.validate_date_format(fromDateTime)
        if not from_date_validation.is_valid:
            logger.warning(f"Invalid fromDateTime parameter: {fromDateTime}")
            return format_error_response(CommonErrors.invalid_parameter(
                "fromDateTime", 
                fromDateTime, 
                from_date_validation.error_message
            ))
        params['fromDateTime'] = fromDateTime
    
    if toDateTime is not None:
        to_date_validation = ParameterValidator.validate_date_format(toDateTime)
        if not to_date_validation.is_valid:
            logger.warning(f"Invalid toDateTime parameter: {toDateTime}")
            return format_error_response(CommonErrors.invalid_parameter(
                "toDateTime", 
                toDateTime, 
                to_date_validation.error_message
            ))
        params['toDateTime'] = toDateTime
    
    try:
        data = await safe_congressional_request("/committee-report", ctx, params, endpoint_type='committee-reports')
        
        if not data or 'reports' not in data:
            logger.warning("No committee reports data received from search")
            return format_error_response(CommonErrors.data_not_found("committee reports"))
        
        # Process and clean response - use reports data directly since base endpoint returns 'reports'
        reports_data = data['reports']
        if not reports_data:
            logger.info("No committee reports found in search")
            return format_error_response(CommonErrors.data_not_found("committee reports"))
        
        # Apply deduplication and sorting manually since clean_committee_reports_response expects 'committeeReports'
        from congress_api.core.response_utils import CommitteeReportsProcessor
        
        # Deduplicate and sort
        deduplicated_reports = CommitteeReportsProcessor.deduplicate_reports(reports_data)
        sorted_reports = sorted(deduplicated_reports, key=lambda x: x.get('updateDate', ''), reverse=True)
        limited_reports = sorted_reports[:limit]
        
        logger.info(f"Found {len(limited_reports)} committee reports matching search criteria")
        
        # Format results
        formatted_reports = []
        for report in limited_reports:
            formatted_reports.append(format_committee_report_item(report))
        
        result = f"# Committee Reports Search Results ({len(limited_reports)} found)\n\n"
        result += "\n\n---\n\n".join(formatted_reports)
        
        return result
        
    except Exception as e:
        logger.error(f"Error searching committee reports: {str(e)}")
        return format_error_response(CommonErrors.api_server_error(
            "Failed to search committee reports",
            message=str(e)
        ))

# @require_paid_access
async def get_committee_report_content(
    ctx: Context,
    congress: int, 
    report_type: str, 
    report_number: int,
    chunk_number: int = 1,
    chunk_size: int = 8000
) -> str:
    """
    Get the actual text content of a specific committee report, with chunking support for large reports.
    
    Args:
        congress: Congress number (e.g., 117 for 117th Congress)
        report_type: Report type (e.g., 'hrpt' for House Report, 'srpt' for Senate Report)
        report_number: Report number
        chunk_number: Chunk number to retrieve (1-based, default: 1)
        chunk_size: Size of each chunk in characters (default: 8000)
    """
    logger.debug(f"Fetching content for committee report {congress}/{report_type}/{report_number}")
    
    # Validate congress parameter
    validation = ParameterValidator.validate_congress_number(congress)
    if not validation.is_valid:
        logger.warning(f"Invalid congress number: {congress}")
        return format_error_response(CommonErrors.invalid_congress_number(congress))
    
    # Validate report type
    report_type_validation = ParameterValidator.validate_report_type(report_type)
    if not report_type_validation.is_valid:
        logger.warning(f"Invalid report type: {report_type}")
        return format_error_response(CommonErrors.invalid_parameter(
            "report_type", 
            report_type, 
            report_type_validation.error_message
        ))
    report_type = report_type_validation.sanitized_value
    
    # Validate report number
    report_number_validation = ParameterValidator.validate_report_number(report_number)
    if not report_number_validation.is_valid:
        logger.warning(f"Invalid report number: {report_number}")
        return format_error_response(CommonErrors.invalid_parameter(
            "report_number", 
            report_number, 
            report_number_validation.error_message
        ))
    
    # Validate chunk_number parameter
    if not isinstance(chunk_number, int) or chunk_number < 1:
        error_response = CommonErrors.invalid_parameter(
            "chunk_number", 
            chunk_number, 
            "Chunk number must be a positive integer (1-based)"
        )
        return format_error_response(error_response)
    
    # Validate chunk_size parameter
    if not isinstance(chunk_size, int) or chunk_size < 1000 or chunk_size > 50000:
        error_response = CommonErrors.invalid_parameter(
            "chunk_size", 
            chunk_size, 
            "Chunk size must be between 1000 and 50000 characters"
        )
        return format_error_response(error_response)
    
    try:
        # First, get the text versions to find the content URL
        endpoint = f"/committee-report/{congress}/{report_type}/{report_number}/text"
        data = await safe_congressional_request(endpoint, ctx, {})
        
        if not data or 'text' not in data:
            logger.warning(f"No text versions data received for committee report {congress}/{report_type}/{report_number}")
            return format_error_response(CommonErrors.data_not_found(
                "committee report text versions", 
                {"congress": congress, "report_type": report_type, "report_number": report_number}
            ))
        
        text_versions = data['text']
        if not text_versions:
            logger.info(f"No text versions found for committee report {congress}/{report_type}/{report_number}")
            return format_error_response(CommonErrors.data_not_found(
                "committee report text versions", 
                {"congress": congress, "report_type": report_type, "report_number": report_number}
            ))
        
        # Get the formatted text URL (prefer HTML format)
        text_url = None
        selected_format = None
        
        # Look through all text versions for a formatted text URL
        for text_version in text_versions:
            formats = text_version.get("formats", [])
            for fmt in formats:
                if fmt.get("type") == "Formatted Text":
                    text_url = fmt.get("url")
                    selected_format = fmt
                    break
            if text_url:
                break
        
        if not text_url:
            # If no formatted text, try to get any available format
            for text_version in text_versions:
                formats = text_version.get("formats", [])
                if formats:
                    text_url = formats[0].get("url")
                    selected_format = formats[0]
                    break
        
        if not text_url:
            available_formats = []
            for text_version in text_versions:
                for fmt in text_version.get("formats", []):
                    available_formats.append(fmt.get("type", "Unknown"))
            
            error_response = CommonErrors.data_not_found("committee report content", {
                "congress": congress,
                "report_type": report_type,
                "report_number": report_number,
                "available_formats": available_formats
            })
            return format_error_response(error_response)
        
        # Fetch the actual committee report text content
        try:
            # Configure HTTP client with proper headers and timeout
            headers = {
                'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
            }
            timeout = httpx.Timeout(30.0)  # 30 second timeout
            
            async with httpx.AsyncClient(headers=headers, timeout=timeout) as client:
                logger.debug(f"Fetching content from URL: {text_url}")
                response = await client.get(text_url)
                
                logger.debug(f"HTTP response status: {response.status_code}")
                if response.status_code != 200:
                    error_response = CommonErrors.api_server_error("committee report content retrieval")
                    error_response.details = {
                        "http_status": response.status_code,
                        "url": text_url,
                        "response_text": response.text[:500] if response.text else "No response text"
                    }
                    return format_error_response(error_response)
                
                html_content = response.text
                
                # Extract text from HTML and clean it up
                # Remove script and style elements
                html_content = re.sub(r'<script[^>]*>.*?</script>', '', html_content, flags=re.DOTALL | re.IGNORECASE)
                html_content = re.sub(r'<style[^>]*>.*?</style>', '', html_content, flags=re.DOTALL | re.IGNORECASE)
                
                # Remove HTML tags but preserve some structure
                clean_text = re.sub(r'<[^>]+>', '', html_content)
                
                # Clean up whitespace and formatting
                clean_text = re.sub(r'\n\s*\n\s*\n', '\n\n', clean_text)  # Multiple newlines to double
                clean_text = re.sub(r'[ \t]+', ' ', clean_text)  # Multiple spaces to single
                clean_text = clean_text.strip()
                
                # Calculate chunking
                total_chars = len(clean_text)
                total_chunks = (total_chars + chunk_size - 1) // chunk_size  # Ceiling division
                
                if chunk_number < 1 or chunk_number > total_chunks:
                    error_response = CommonErrors.invalid_parameter(
                        "chunk_number", 
                        chunk_number, 
                        f"Invalid chunk number. Report has {total_chunks} chunks of {chunk_size} characters each"
                    )
                    return format_error_response(error_response)
                
                # Extract the requested chunk
                start_pos = (chunk_number - 1) * chunk_size
                end_pos = min(start_pos + chunk_size, total_chars)
                chunk_text = clean_text[start_pos:end_pos]
                
                # Add some overlap context if not the first chunk
                if chunk_number > 1 and start_pos > 200:
                    overlap_start = max(0, start_pos - 200)
                    overlap_text = clean_text[overlap_start:start_pos]
                    chunk_text = f"[...previous context: {overlap_text[-200:]}]\n\n{chunk_text}"
                
                result = [
                    f"# Committee Report {report_type.upper()} {report_number} - {congress}th Congress",
                    f"**Format:** {selected_format.get('type', 'Unknown')}",
                    f"**Chunk:** {chunk_number} of {total_chunks} (characters {start_pos+1:,}-{end_pos:,} of {total_chars:,})",
                    f"**Source:** {text_url}",
                    "",
                    "## Report Content",
                    "",
                    chunk_text
                ]
                
                if chunk_number < total_chunks:
                    result.extend([
                        "",
                        f"📄 **Note**: This is chunk {chunk_number} of {total_chunks}. Use `chunk_number={chunk_number + 1}` to get the next chunk."
                    ])
                
                return "\n".join(result)
                
        except httpx.TimeoutException:
            logger.error(f"Timeout while fetching committee report content from: {text_url}")
            error_response = CommonErrors.api_server_error("committee report content retrieval")
            error_response.details = {
                "error": "Request timeout",
                "url": text_url,
                "suggestion": "The content server may be temporarily slow. Please try again."
            }
            return format_error_response(error_response)
            
        except httpx.RequestError as e:
            logger.error(f"Request error while fetching committee report content: {e}")
            error_response = CommonErrors.api_server_error("committee report content retrieval")
            error_response.details = {
                "error": f"Network error: {str(e)}",
                "url": text_url,
                "suggestion": "Please check your internet connection and try again."
            }
            return format_error_response(error_response)
            
        except Exception as e:
            logger.error(f"Unexpected error while fetching committee report content: {e}")
            error_response = CommonErrors.api_server_error("committee report content retrieval")
            error_response.details = {
                "error": f"Unexpected error: {str(e)}",
                "url": text_url
            }
            return format_error_response(error_response)
        
    except Exception as e:
        logger.error(f"Error fetching committee report content: {str(e)}")
        return format_error_response(CommonErrors.api_server_error(
            "Failed to fetch committee report content",
            message=str(e)
        ))
