# congress_api/features/committee_prints.py
import logging
from typing import Dict, List, Any, Optional
from mcp.server.fastmcp import Context
from ..mcp_app import mcp
from ..core.client_handler import make_api_request
from ..core.api_wrapper import safe_congressional_request
from ..core.validators import ParameterValidator, ValidationResult
from ..core.exceptions import APIErrorResponse, ErrorType, format_error_response, CommonErrors
from ..core.response_utils import CommitteePrintsProcessor, clean_committee_prints_response

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

# --- Formatting Functions ---

def format_committee_print_item(print_item: Dict[str, Any]) -> str:
    """Formats a single committee print item for display in a list."""
    lines = [
        f"Chamber: {print_item.get('chamber', 'N/A')}",
        f"Congress: {print_item.get('congress', 'N/A')}",
        f"Jacket Number: {print_item.get('jacketNumber', 'N/A')}",
        f"Update Date: {print_item.get('updateDate', 'N/A')}",
        f"URL: {print_item.get('url', 'N/A')}"
    ]
    return "\n".join(lines)

def format_committee_print_detail(print_item: Dict[str, Any]) -> str:
    """Formats detailed information for a single committee print."""
    lines = [
        f"Title: {print_item.get('title', 'N/A')}",
        f"Citation: {print_item.get('citation', 'N/A')}",
        f"Congress: {print_item.get('congress', 'N/A')}",
        f"Chamber: {print_item.get('chamber', 'N/A')}",
        f"Jacket Number: {print_item.get('jacketNumber', 'N/A')}",
        f"Number: {print_item.get('number', 'N/A')}",
        f"Update Date: {print_item.get('updateDate', 'N/A')}"
    ]
    
    if 'associatedBills' in print_item and print_item['associatedBills']:
        lines.append("Associated Bills:")
        for bill in print_item['associatedBills']:
            lines.append(f"  - {bill.get('type', '')}{bill.get('number', '')} (Congress {bill.get('congress', '')}) - URL: {bill.get('url', 'N/A')}")
    
    if 'committees' in print_item and print_item['committees']:
        lines.append("Committees:")
        for committee in print_item['committees']:
            lines.append(f"  - {committee.get('name', 'N/A')} (System Code: {committee.get('systemCode', 'N/A')}) - URL: {committee.get('url', 'N/A')}")
    
    if 'text' in print_item and print_item['text'].get('url'):
        lines.append(f"Text Versions URL: {print_item['text']['url']} (Count: {print_item['text'].get('count', 'N/A')})")
        
    return "\n".join(lines)

def format_committee_print_text_version(text_item: Dict[str, Any]) -> str:
    """Formats a single text version item."""
    lines = [
        f"  Type: {text_item.get('type', 'N/A')}",
        f"    URL: {text_item.get('url', 'N/A')}",
        f"    Is Errata: {text_item.get('isErrata', 'N/A')}"
    ]
    return "\n".join(lines)

# --- MCP Tools ---

# @require_paid_access
async def get_latest_committee_prints(ctx: Context) -> str:
    """
    Get a list of the most recent committee prints.
    Returns the 10 most recently updated prints by default.
    """
    # Parameter validation
    limit = 10
    limit_result = ParameterValidator.validate_limit_range(limit)
    if not limit_result.is_valid:
        error = CommonErrors.invalid_parameter(
            "limit", limit, limit_result.error_message
        )
        logger.error(f"Parameter validation failed: {limit_result.error_message}")
        return format_error_response(error)
    
    params = {
        "limit": limit,
        "sort": "updateDate+desc",
        "format": "json"
    }
    
    logger.debug("Fetching latest committee prints with reliability framework")
    try:
        data = await safe_congressional_request("/committee-print", ctx, params, endpoint_type='committee-prints')
        
        if "error" in data:
            error = CommonErrors.api_server_error(
                f"Failed to retrieve latest committee prints: {data.get('error', 'Unknown API error')}"
            )
            logger.error(f"API request failed: {data['error']}")
            return format_error_response(error)
        
        prints = data.get("committeePrints", [])
        if not prints:
            logger.info("No committee prints found")
            return "No committee prints found."
        
        # Process response with deduplication and sorting
        processed_prints = CommitteePrintsProcessor.deduplicate_committee_prints(prints)
        processed_prints = CommitteePrintsProcessor.sort_prints_by_update_date(processed_prints)
        
        logger.info(f"Found {len(processed_prints)} committee prints")
        lines = ["Latest Committee Prints:"]
        for print_item in processed_prints:
            lines.append("")
            lines.append(format_committee_print_item(print_item))
        
        return "\n".join(lines)
        
    except Exception as e:
        error = CommonErrors.api_server_error(
            f"Failed to retrieve latest committee prints: {str(e)}"
        )
        logger.error(f"API request failed: {str(e)}")
        return format_error_response(error)

# @require_paid_access
async def get_committee_prints_by_congress(ctx: Context, congress: int) -> str:
    """
    Get committee prints for a specific Congress.
    
    Args:
        congress: The Congress number (e.g., 117).
    """
    # Parameter validation
    congress_result = ParameterValidator.validate_congress_number(congress)
    if not congress_result.is_valid:
        error = CommonErrors.invalid_parameter(
            "congress", congress, congress_result.error_message
        )
        logger.error(f"Parameter validation failed: {congress_result.error_message}")
        return format_error_response(error)
    
    limit = 20
    limit_result = ParameterValidator.validate_limit_range(limit)
    if not limit_result.is_valid:
        error = CommonErrors.invalid_parameter(
            "limit", limit, limit_result.error_message
        )
        logger.error(f"Parameter validation failed: {limit_result.error_message}")
        return format_error_response(error)
    
    params = {
        "limit": limit,
        "sort": "updateDate+desc",
        "format": "json"
    }
    
    logger.debug(f"Fetching committee prints for Congress {congress} with reliability framework")
    try:
        data = await safe_congressional_request(f"/committee-print/{congress}", ctx, params)
        
        if "error" in data:
            error = CommonErrors.api_server_error(
                f"Failed to retrieve committee prints for Congress {congress}: {data.get('error', 'Unknown API error')}"
            )
            logger.error(f"API request failed: {data['error']}")
            return format_error_response(error)
        
        prints = data.get("committeePrints", [])
        if not prints:
            logger.info(f"No committee prints found for Congress {congress}")
            return f"No committee prints found for Congress {congress}."
        
        # Process response with deduplication and sorting
        processed_prints = CommitteePrintsProcessor.deduplicate_committee_prints(prints)
        processed_prints = CommitteePrintsProcessor.sort_prints_by_update_date(processed_prints)
        
        logger.info(f"Found {len(processed_prints)} committee prints for Congress {congress}")
        lines = [f"Committee Prints for Congress {congress}:"]
        for print_item in processed_prints:
            lines.append("")
            lines.append(format_committee_print_item(print_item))
        
        return "\n".join(lines)
        
    except Exception as e:
        error = CommonErrors.api_server_error(
            f"Failed to retrieve committee prints for Congress {congress}: {str(e)}"
        )
        logger.error(f"API request failed: {str(e)}")
        return format_error_response(error)

# @require_paid_access
async def get_committee_prints_by_congress_and_chamber(ctx: Context, congress: int, chamber: str) -> str:
    """
    Get committee prints for a specific Congress and chamber.
    
    Args:
        congress: The Congress number (e.g., 117).
        chamber: The chamber name (e.g., "house", "senate").
    """
    # Parameter validation
    congress_result = ParameterValidator.validate_congress_number(congress)
    if not congress_result.is_valid:
        error = CommonErrors.invalid_parameter(
            "congress", congress, congress_result.error_message
        )
        logger.error(f"Parameter validation failed: {congress_result.error_message}")
        return format_error_response(error)
    
    chamber_result = ParameterValidator.validate_chamber(chamber)
    if not chamber_result.is_valid:
        error = CommonErrors.invalid_parameter(
            "chamber", chamber, chamber_result.error_message
        )
        logger.error(f"Parameter validation failed: {chamber_result.error_message}")
        return format_error_response(error)
    
    limit = 20
    limit_result = ParameterValidator.validate_limit_range(limit)
    if not limit_result.is_valid:
        error = CommonErrors.invalid_parameter(
            "limit", limit, limit_result.error_message
        )
        logger.error(f"Parameter validation failed: {limit_result.error_message}")
        return format_error_response(error)
    
    params = {
        "limit": limit,
        "sort": "updateDate+desc",
        "format": "json"
    }
    
    logger.debug(f"Fetching committee prints for Congress {congress}, chamber {chamber} with reliability framework")
    try:
        data = await safe_congressional_request(f"/committee-print/{congress}/{chamber}", ctx, params)
        
        if "error" in data:
            error = CommonErrors.api_server_error(
                f"Failed to retrieve committee prints for Congress {congress}, {chamber}: {data.get('error', 'Unknown API error')}"
            )
            logger.error(f"API request failed: {data['error']}")
            return format_error_response(error)
        
        prints = data.get("committeePrints", [])
        if not prints:
            logger.info(f"No committee prints found for Congress {congress}, chamber {chamber}")
            return f"No committee prints found for Congress {congress}, chamber {chamber}."
        
        # Process response with deduplication and sorting
        processed_prints = CommitteePrintsProcessor.deduplicate_committee_prints(prints)
        processed_prints = CommitteePrintsProcessor.sort_prints_by_update_date(processed_prints)
        
        logger.info(f"Found {len(processed_prints)} committee prints for Congress {congress}, chamber {chamber}")
        lines = [f"Committee Prints for Congress {congress}, Chamber {chamber.title()}:"]
        for print_item in processed_prints:
            lines.append("")
            lines.append(format_committee_print_item(print_item))
        
        return "\n".join(lines)
        
    except Exception as e:
        error = CommonErrors.api_server_error(
            f"Failed to retrieve committee prints for Congress {congress}, {chamber}: {str(e)}"
        )
        logger.error(f"API request failed: {str(e)}")
        return format_error_response(error)

# @require_paid_access
async def get_committee_print_details(ctx: Context, congress: int, chamber: str, jacket_number: int) -> str:
    """
    Get detailed information about a specific committee print.
    
    Args:
        congress: The Congress number (e.g., 117).
        chamber: The chamber name (e.g., "house", "senate").
        jacket_number: The jacket number for the committee print.
    """
    # Parameter validation
    congress_result = ParameterValidator.validate_congress_number(congress)
    if not congress_result.is_valid:
        error = CommonErrors.invalid_parameter(
            "congress", congress, congress_result.error_message
        )
        logger.error(f"Parameter validation failed: {congress_result.error_message}")
        return format_error_response(error)
    
    chamber_result = ParameterValidator.validate_chamber(chamber)
    if not chamber_result.is_valid:
        error = CommonErrors.invalid_parameter(
            "chamber", chamber, chamber_result.error_message
        )
        logger.error(f"Parameter validation failed: {chamber_result.error_message}")
        return format_error_response(error)
    
    jacket_result = ParameterValidator.validate_jacket_number(jacket_number)
    if not jacket_result.is_valid:
        error = CommonErrors.invalid_parameter(
            "jacket_number", jacket_number, jacket_result.error_message
        )
        logger.error(f"Parameter validation failed: {jacket_result.error_message}")
        return format_error_response(error)
    
    logger.debug(f"Fetching committee print details for Congress {congress}, chamber {chamber}, jacket {jacket_number} with reliability framework")
    try:
        data = await safe_congressional_request(f"/committee-print/{congress}/{chamber}/{jacket_number}", ctx)
        
        # Handle different response structures
        if isinstance(data, list):
            # If response is a list, check if it's empty or has error info
            if not data:
                error = CommonErrors.data_not_found(
                    "committee print",
                    identifier=f"Congress {congress}, chamber {chamber}, jacket number {jacket_number}"
                )
                logger.info(f"Committee print not found: Congress {congress}, chamber {chamber}, jacket {jacket_number}")
                return format_error_response(error)
            # If it's a list with one item, use that item
            print_item = data[0] if data else None
        else:
            # If response is a dict, check for error or committeePrint
            if "error" in data:
                error = CommonErrors.api_server_error(
                    f"Failed to retrieve committee print details: {data.get('error', 'Unknown API error')}"
                )
                logger.error(f"API request failed: {data['error']}")
                return format_error_response(error)
            
            print_item = data.get("committeePrint")
        
        if not print_item:
            error = CommonErrors.data_not_found(
                "committee print",
                identifier=f"Congress {congress}, chamber {chamber}, jacket number {jacket_number}"
            )
            logger.info(f"Committee print not found: Congress {congress}, chamber {chamber}, jacket {jacket_number}")
            return format_error_response(error)
        
        logger.debug(f"Committee print data type: {type(print_item)}")
        logger.debug(f"Committee print data: {print_item}")
        logger.info(f"Found committee print details for Congress {congress}, chamber {chamber}, jacket {jacket_number}")
        
        # Ensure print_item is a dictionary before passing to format function
        if isinstance(print_item, list):
            if len(print_item) > 0:
                print_item = print_item[0]
            else:
                error = CommonErrors.data_not_found(
                    "committee print",
                    identifier=f"Congress {congress}, chamber {chamber}, jacket number {jacket_number}"
                )
                logger.info(f"Empty committee print list: Congress {congress}, chamber {chamber}, jacket {jacket_number}")
                return format_error_response(error)
        
        return format_committee_print_detail(print_item)
        
    except Exception as e:
        error = CommonErrors.api_server_error(
            f"Failed to retrieve committee print details: {str(e)}"
        )
        logger.error(f"API request failed: {str(e)}")
        return format_error_response(error)

# @require_paid_access
async def get_committee_print_text_versions(ctx: Context, congress: int, chamber: str, jacket_number: int) -> str:
    """
    Get text versions for a specific committee print.
    
    Args:
        congress: The Congress number (e.g., 117).
        chamber: The chamber name (e.g., "house", "senate").
        jacket_number: The jacket number for the committee print.
    """
    # Parameter validation
    congress_result = ParameterValidator.validate_congress_number(congress)
    if not congress_result.is_valid:
        error = CommonErrors.invalid_parameter(
            "congress", congress, congress_result.error_message
        )
        logger.error(f"Parameter validation failed: {congress_result.error_message}")
        return format_error_response(error)
    
    chamber_result = ParameterValidator.validate_chamber(chamber)
    if not chamber_result.is_valid:
        error = CommonErrors.invalid_parameter(
            "chamber", chamber, chamber_result.error_message
        )
        logger.error(f"Parameter validation failed: {chamber_result.error_message}")
        return format_error_response(error)
    
    jacket_result = ParameterValidator.validate_jacket_number(jacket_number)
    if not jacket_result.is_valid:
        error = CommonErrors.invalid_parameter(
            "jacket_number", jacket_number, jacket_result.error_message
        )
        logger.error(f"Parameter validation failed: {jacket_result.error_message}")
        return format_error_response(error)
    
    logger.debug(f"Fetching committee print text versions for Congress {congress}, chamber {chamber}, jacket {jacket_number} with reliability framework")
    try:
        data = await safe_congressional_request(f"/committee-print/{congress}/{chamber}/{jacket_number}/text", ctx)
        
        logger.debug(f"Text versions API response type: {type(data)}")
        logger.debug(f"Text versions API response: {data}")
        
        # Handle different response structures
        if isinstance(data, list):
            # If response is a list, it should contain text versions directly
            text_versions = data
        else:
            # If response is a dict, check for error or textVersions
            if "error" in data:
                error = CommonErrors.api_server_error(
                    f"Failed to retrieve committee print text versions: {data.get('error', 'Unknown API error')}"
                )
                logger.error(f"API request failed: {data['error']}")
                return format_error_response(error)
            
            text_versions = data.get("textVersions", [])
        
        logger.debug(f"Extracted text_versions: {text_versions}")
        
        if not text_versions:
            error = CommonErrors.data_not_found(
                "text versions",
                identifier=f"committee print Congress {congress}, chamber {chamber}, jacket number {jacket_number}"
            )
            logger.info(f"No text versions found for committee print: Congress {congress}, chamber {chamber}, jacket {jacket_number}")
            return format_error_response(error)
        
        logger.info(f"Found {len(text_versions)} text versions for committee print Congress {congress}, chamber {chamber}, jacket {jacket_number}")
        lines = [f"Text Versions for Committee Print {congress}/{chamber}/{jacket_number}:"]
        for version in text_versions:
            lines.append("")
            lines.append(format_committee_print_text_version(version))
        
        return "\n".join(lines)
        
    except Exception as e:
        error = CommonErrors.api_server_error(
            f"Failed to retrieve committee print text versions: {str(e)}"
        )
        logger.error(f"API request failed: {str(e)}")
        return format_error_response(error)

# @require_paid_access
async def search_committee_prints(
    ctx: Context,
    offset: Optional[int] = None,
    limit: Optional[int] = None,
    from_date_time: Optional[str] = None,
    to_date_time: Optional[str] = None
) -> str:
    """
    Search for committee prints based on various criteria.
    
    Args:
        offset: The starting record for pagination (optional)
        limit: The number of records to return (max 250, optional)
        from_date_time: Start date for filtering by update date (YYYY-MM-DDT00:00:00Z, optional)
        to_date_time: End date for filtering by update date (YYYY-MM-DDT00:00:00Z, optional)
    """
    # Validate parameters
    if offset is not None:
        if not isinstance(offset, int) or offset < 0:
            error = CommonErrors.invalid_parameter(
                "offset", offset, "Offset must be a non-negative integer"
            )
            logger.error(f"Parameter validation failed: Invalid offset {offset}")
            return format_error_response(error)
    
    if limit is not None:
        limit_result = ParameterValidator.validate_limit_range(limit, max_limit=250)
        if not limit_result.is_valid:
            error = CommonErrors.invalid_parameter(
                "limit", limit, limit_result.error_message
            )
            logger.error(f"Parameter validation failed: {limit_result.error_message}")
            return format_error_response(error)
    
    if from_date_time is not None:
        # Basic date format validation - should be ISO format like YYYY-MM-DDTHH:MM:SSZ
        if not isinstance(from_date_time, str) or len(from_date_time) < 10:
            error = CommonErrors.invalid_parameter(
                "from_date_time", from_date_time, "Date must be in ISO format (YYYY-MM-DDTHH:MM:SSZ)"
            )
            logger.error(f"Parameter validation failed: Invalid from_date_time format")
            return format_error_response(error)
    
    if to_date_time is not None:
        # Basic date format validation - should be ISO format like YYYY-MM-DDTHH:MM:SSZ
        if not isinstance(to_date_time, str) or len(to_date_time) < 10:
            error = CommonErrors.invalid_parameter(
                "to_date_time", to_date_time, "Date must be in ISO format (YYYY-MM-DDTHH:MM:SSZ)"
            )
            logger.error(f"Parameter validation failed: Invalid to_date_time format")
            return format_error_response(error)
    
    # Build parameters
    params = {
        "format": "json"
    }
    
    if offset is not None:
        params["offset"] = offset
    if limit is not None:
        params["limit"] = limit
    if from_date_time is not None:
        params["fromDateTime"] = from_date_time
    if to_date_time is not None:
        params["toDateTime"] = to_date_time
    
    logger.debug(f"Searching committee prints with reliability framework: offset={offset}, limit={limit}, from_date={from_date_time}, to_date={to_date_time}")
    try:
        data = await safe_congressional_request("/committee-print", ctx, params, endpoint_type='committee-prints')
        
        if "error" in data:
            error = CommonErrors.api_server_error(
                f"Failed to search committee prints: {data.get('error', 'Unknown API error')}"
            )
            logger.error(f"API request failed: {data['error']}")
            return format_error_response(error)
        
        prints = data.get("committeePrints", [])
        if not prints:
            logger.info("No committee prints found for search criteria")
            return "No committee prints found for the specified criteria."
        
        # Process response with deduplication and sorting
        processed_prints = CommitteePrintsProcessor.deduplicate_committee_prints(prints)
        processed_prints = CommitteePrintsProcessor.sort_prints_by_update_date(processed_prints)
        
        # Apply limit to processed results
        if limit and len(processed_prints) > limit:
            processed_prints = processed_prints[:limit]
        
        logger.info(f"Found {len(processed_prints)} committee prints matching search criteria")
        lines = ["Committee Prints Search Results:"]
        for print_item in processed_prints:
            lines.append("")
            lines.append(format_committee_print_item(print_item))
        
        return "\n".join(lines)
        
    except Exception as e:
        error = CommonErrors.api_server_error(
            f"Failed to search committee prints: {str(e)}"
        )
        logger.error(f"API request failed: {str(e)}")
        return format_error_response(error)
