import logging
from typing import Dict, List, Any, Optional
from mcp.server.fastmcp import Context
from ..mcp_app import mcp
from ..core.api_wrapper import safe_congressional_request
from ..core.validators import ParameterValidator
from ..core.exceptions import CommonErrors, format_error_response
from ..core.response_utils import SenateCommunicationsProcessor, clean_senate_communications_response

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

# --- Formatting Helpers ---

def format_senate_communication_item(item: Dict[str, Any]) -> str:
    """Formats a single senate communication item for display in a list."""
    lines = [
        f"**Congress:** {item.get('congress', 'N/A')}",
        f"**Chamber:** {item.get('chamber', 'N/A')}",
        f"**Communication Number:** {item.get('communicationNumber', item.get('number', 'N/A'))}"
    ]
    
    # Add communication type if available
    if 'communicationType' in item:
        comm_type = item['communicationType']
        lines.append(f"**Type:** {comm_type.get('name', 'N/A')} ({comm_type.get('code', 'N/A')})")
    
    # Add update date if available
    if 'updateDate' in item:
        lines.append(f"**Update Date:** {item.get('updateDate', 'N/A')}")
    
    # Add URL if available
    if 'url' in item:
        lines.append(f"**URL:** {item.get('url', 'N/A')}")
    
    return "\n".join(lines)

def format_senate_communication_detail(comm_data: Dict[str, Any]) -> str:
    """Formats detailed information for a senate communication."""
    if not comm_data:
        return "No senate communication data available."
    
    # Check if the expected key is present
    if 'senateCommunication' not in comm_data:
        # Try to determine if this is a valid response in a different format
        if isinstance(comm_data, dict) and len(comm_data) > 0:
            # Log what keys we did receive
            logger.debug(f"Received keys in response: {list(comm_data.keys())}")
            return f"Received senate communication data, but in an unexpected format. Keys: {list(comm_data.keys())}"
        return "No senate communication data available."
    
    comm = comm_data['senateCommunication']
    
    lines = [
        f"# Senate Communication - {comm.get('congress', 'N/A')}/{comm.get('communicationType', {}).get('code', 'N/A')}/{comm.get('number', 'N/A')}",
        "",
        f"**Congress:** {comm.get('congress', 'N/A')}",
        f"**Chamber:** {comm.get('chamber', 'N/A')}",
        f"**Session:** {comm.get('sessionNumber', 'N/A')}"
    ]
    
    # Add communication type if available
    if 'communicationType' in comm:
        comm_type = comm['communicationType']
        lines.append(f"**Type:** {comm_type.get('name', 'N/A')} ({comm_type.get('code', 'N/A')})")
    
    # Add abstract if available
    if 'abstract' in comm:
        lines.extend(["", f"**Abstract:** {comm.get('abstract', 'N/A')}"])
    
    # Add congressional record date if available
    if 'congressionalRecordDate' in comm:
        lines.append(f"**Congressional Record Date:** {comm.get('congressionalRecordDate', 'N/A')}")
    
    # Add committees if available
    if 'committees' in comm and comm['committees']:
        lines.extend(["", "**Referred to Committees:**"])
        for committee in comm['committees']:
            lines.append(f"  - {committee.get('name', 'N/A')}")
            lines.append(f"    Referral Date: {committee.get('referralDate', 'N/A')}")
            if 'systemCode' in committee:
                lines.append(f"    System Code: {committee.get('systemCode', 'N/A')}")
            if 'url' in committee:
                lines.append(f"    URL: {committee.get('url', 'N/A')}")
    
    # Add update date if available
    if 'updateDate' in comm:
        lines.extend(["", f"**Update Date:** {comm.get('updateDate', 'N/A')}"])
    
    return "\n".join(lines)

def format_senate_communications_list(communications: List[Dict[str, Any]], title: str = "Senate Communications") -> str:
    """Format a list of senate communications with enhanced markdown formatting."""
    if not communications:
        return f"No {title.lower()} found."
    
    lines = [f"# {title}", f"", f"Found **{len(communications)}** communications:", ""]
    
    for i, comm in enumerate(communications, 1):
        lines.extend([f"## {i}. Communication {comm.get('congress', 'N/A')}/{comm.get('communicationType', {}).get('code', 'N/A')}/{comm.get('communicationNumber', comm.get('number', 'N/A'))}", ""])
        lines.append(format_senate_communication_item(comm))
        lines.append("")
    
    return "\n".join(lines)

# --- MCP Resources ---

# @require_paid_access
@mcp.resource("congress://senate-communications/latest")
async def get_latest_senate_communications(ctx: Context) -> str:
    """
    Get the most recent senate communications.
    Returns the 10 most recently published communications by default.
    """
    try:
        params = {
            "limit": 10,
            "format": "json"
        }
        
        logger.debug("Fetching latest senate communications")
        data = await safe_congressional_request("/senate-communication", ctx, params, endpoint_type='senate_communications')
        
        # Process response using reliability framework
        processed_communications = clean_senate_communications_response(data, limit=10)
        
        if not processed_communications:
            logger.info("No senate communications found")
            return "No senate communications found."
        
        logger.info(f"Found {len(processed_communications)} senate communications")
        return format_senate_communications_list(processed_communications, "Latest Senate Communications")
        
    except Exception as e:
        logger.error(f"Error in get_latest_senate_communications: {str(e)}")
        return CommonErrors.api_server_error("/senate-communication", str(e))

# --- MCP Tools ---

# @require_paid_access
async def get_senate_communication_details(
    ctx: Context,
    congress: int,
    communication_type: str,
    communication_number: int
) -> str:
    """
    Get detailed information for a specific senate communication.
    
    Args:
        congress: The Congress number (e.g., 117).
        communication_type: The type of communication (e.g., "ec", "pm", "pom").
        communication_number: The communication number (e.g., 2561).
    """
    try:
        # Validate parameters
        congress_validation = ParameterValidator.validate_congress_number(congress)
        if not congress_validation.is_valid:
            return format_error_response(CommonErrors.invalid_congress_number(congress))
        
        type_validation = ParameterValidator.validate_senate_communication_type(communication_type)
        if not type_validation.is_valid:
            return format_error_response(CommonErrors.invalid_parameter("communication_type", communication_type, type_validation.error_message))
        
        number_validation = ParameterValidator.validate_communication_number(communication_number)
        if not number_validation.is_valid:
            return format_error_response(CommonErrors.invalid_parameter("communication_number", communication_number, number_validation.error_message))
        
        # Use sanitized values
        congress_clean = congress_validation.sanitized_value or congress
        type_clean = type_validation.sanitized_value or communication_type
        number_clean = number_validation.sanitized_value or communication_number
        
        params = {"format": "json"}
        
        logger.debug(f"Fetching senate communication {congress_clean}/{type_clean}/{number_clean}")
        data = await safe_congressional_request(f"/senate-communication/{congress_clean}/{type_clean}/{number_clean}", ctx, params, endpoint_type='senate_communications')
        
        # Check for different possible response formats
        if 'senateCommunication' in data:
            logger.info(f"Retrieved senate communication using 'senateCommunication' key")
            return format_senate_communication_detail(data)
        else:
            # If the expected key is not found, log the keys and return a formatted version of whatever we got
            logger.warning(f"Unexpected response format. Keys: {list(data.keys()) if isinstance(data, dict) else 'Not a dictionary'}")
            return f"Retrieved senate communication {congress_clean}/{type_clean}/{number_clean}, but in an unexpected format:\n\n{str(data)[:500]}..."
            
    except Exception as e:
        logger.error(f"Error in get_senate_communication_details: {str(e)}")
        return CommonErrors.api_server_error(f"/senate-communication/{congress}/{communication_type}/{communication_number}", str(e))

# @require_paid_access
async def search_senate_communications(
    ctx: Context,
    congress: Optional[int] = None,
    communication_type: Optional[str] = None,
    limit: int = 10
) -> str:
    """
    Search for senate communications based on various criteria.
    
    Args:
        congress: Optional Congress number (e.g., 117).
        communication_type: Optional communication type (e.g., "ec", "pm", "pom").
        limit: Maximum number of results to return (default: 10).
    """
    try:
        # Validate parameters
        if congress is not None:
            congress_validation = ParameterValidator.validate_congress_number(congress)
            if not congress_validation.is_valid:
                return format_error_response(CommonErrors.invalid_congress_number(congress))
            congress = congress_validation.sanitized_value or congress
        
        if communication_type is not None:
            type_validation = ParameterValidator.validate_senate_communication_type(communication_type)
            if not type_validation.is_valid:
                return format_error_response(CommonErrors.invalid_parameter("communication_type", communication_type, type_validation.error_message))
            communication_type = type_validation.sanitized_value or communication_type
        
        limit_validation = ParameterValidator.validate_limit_range(limit, 250)
        if not limit_validation.is_valid:
            return format_error_response(CommonErrors.invalid_parameter("limit", limit, limit_validation.error_message))
        
        params = {
            "format": "json",
            "limit": limit
        }
        
        # Construct the endpoint based on provided parameters
        endpoint = "/senate-communication"
        if congress:
            endpoint += f"/{congress}"
            if communication_type:
                endpoint += f"/{communication_type}"
        
        # Log the search parameters
        search_params = []
        if congress:
            search_params.append(f"congress={congress}")
        if communication_type:
            search_params.append(f"communication_type={communication_type}")
        if limit != 10:
            search_params.append(f"limit={limit}")
        
        search_str = ", ".join(search_params) if search_params else "default parameters"
        logger.debug(f"Searching senate communications with {search_str}")
        
        # Make the API request using defensive wrapper
        data = await safe_congressional_request(endpoint, ctx, params, endpoint_type='senate_communications')
        
        # Process response using reliability framework
        processed_communications = clean_senate_communications_response(data, limit=limit)
        
        if not processed_communications:
            logger.info("No senate communications found matching the search criteria")
            return "No senate communications found matching the search criteria."
        
        logger.info(f"Found {len(processed_communications)} senate communications matching the search criteria")
        
        # Format the results with enhanced markdown
        title = "Senate Communications Search Results"
        if congress and communication_type:
            title = f"Senate Communications for Congress {congress}, Type: {communication_type.upper()}"
        elif congress:
            title = f"Senate Communications for Congress {congress}"
        elif communication_type:
            title = f"Senate Communications - Type: {communication_type.upper()}"
        
        return format_senate_communications_list(processed_communications, title)
        
    except Exception as e:
        logger.error(f"Error in search_senate_communications: {str(e)}")
        return CommonErrors.api_server_error("/senate-communication", str(e))
