# committees.py
from typing import Dict, List, Any, Optional
import logging
from mcp.server.fastmcp import Context
from ..mcp_app import mcp
from ..core.client_handler import make_api_request
from ..core.validators import ParameterValidator, ValidationResult
from ..core.api_wrapper import DefensiveAPIWrapper
from ..core.exceptions import CommonErrors, format_error_response
from ..core.response_utils import ResponseProcessor

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

# Initialize defensive API wrapper
defensive_api = DefensiveAPIWrapper()

async def safe_committees_request(endpoint: str, ctx: Context, params: Dict[str, Any] = {}) -> Dict[str, Any]:
    """Safe API request wrapper for committees endpoints."""
    return await DefensiveAPIWrapper.safe_api_request(endpoint, ctx, params, endpoint_type="committees")

# Formatting helpers
def format_committee_summary(committee: Dict[str, Any]) -> str:
    """Format a committee into a readable summary."""
    result = []
    result.append(f"Committee: {committee.get('name', 'Unknown')}")
    result.append(f"Chamber: {committee.get('chamber', 'Unknown')}")
    result.append(f"Committee Code: {committee.get('systemCode', 'Unknown')}")
    result.append(f"URL: {committee.get('url', 'No URL available')}")
    return "\n".join(result)

# Resources (Static/Reference Data)
# - get_committees: List all committees
# - get_committees_by_chamber: List committees by chamber  
# - get_committee_details: Specific committee details

@mcp.resource("congress://committees")
async def get_committees(ctx: Context) -> str:
    """
    Get a list of congressional committees.
    
    Returns a comprehensive list of committees in the House and Senate,
    including their names, chambers, and system codes.
    """
    data = await make_api_request("/committee", ctx)
    
    if "error" in data:
        return f"Error retrieving committees: {data['error']}"
    
    committees = data.get("committees", [])
    if not committees:
        return "No committees found."
    
    result = ["Congressional Committees:"]
    for committee in committees:
        result.append("\n" + format_committee_summary(committee))
    
    return "\n".join(result)

@mcp.resource("congress://committees/{chamber}")
async def get_committees_by_chamber(ctx: Context, chamber: str) -> str:
    """
    Get committees for a specific chamber.
    
    Args:
        chamber: The chamber of Congress ("house" or "senate")
        
    Returns a list of committees in the specified chamber.
    """
    
    # Validate chamber parameter
    if chamber.lower() not in ["house", "senate"]:
        return f"Invalid chamber: {chamber}. Must be 'house' or 'senate'."
    
    # Make API request to get committees
    data = await make_api_request("/committee", ctx)
    
    if "error" in data:
        return f"Error retrieving committees: {data['error']}"
    
    all_committees = data.get("committees", [])
    if not all_committees:
        return f"No committees found."
    
    # Filter committees by chamber
    chamber_lower = chamber.lower()
    committees = [comm for comm in all_committees if comm.get("chamber", "").lower() == chamber_lower]
    
    if not committees:
        return f"No committees found for the {chamber.capitalize()}."
    
    result = [f"{chamber.capitalize()} Committees:"]
    for committee in committees:
        result.append("\n" + format_committee_summary(committee))
    
    return "\n".join(result)

@mcp.resource("congress://committees/{chamber}/{committee_code}")
async def get_committee_details(ctx: Context, chamber: str, committee_code: str) -> str:
    """
    Get detailed information about a specific committee.
    
    Args:
        chamber: The chamber of Congress ("house" or "senate")
        committee_code: The committee code (e.g., "hsag", "ssap")
        
    Returns detailed information about the specified committee.
    """
    # Validate chamber parameter
    if chamber.lower() not in ["house", "senate"]:
        return f"Invalid chamber: {chamber}. Must be 'house' or 'senate'."
    
    endpoint = f"/committee/{chamber.lower()}/{committee_code}"
    committee_data = await make_api_request(endpoint, ctx)
    
    if "error" in committee_data:
        return f"Error retrieving committee: {committee_data['error']}"
    
    committee = committee_data.get("committee", {})
    if not committee:
        return f"No committee found with code {committee_code} in the {chamber.capitalize()}."
    
    result = []
    
    # Committee name and code
    # Extract committee name using multiple possible locations in the response
    name = "Unknown"
    
    # Option 1: Direct name field
    if "name" in committee:
        name = committee["name"]
    
    # Option 2: History array with libraryOfCongressName or officialName
    elif "history" in committee and committee["history"] and len(committee["history"]) > 0:
        history_item = committee["history"][0]
        if "libraryOfCongressName" in history_item and history_item["libraryOfCongressName"]:
            name = history_item["libraryOfCongressName"]
        elif "officialName" in history_item and history_item["officialName"]:
            name = history_item["officialName"]
    
    # Option 3: For subcommittees, the name might be in the parent committee's subcommittees array
    elif "parent" in committee and committee["parent"] and "subcommittees" in committee["parent"]:
        for subcommittee in committee["parent"]["subcommittees"]:
            if subcommittee.get("systemCode") == committee_code:
                name = subcommittee.get("name", "Unknown")
                break
    
    # Option 4: Check for a 'title' field that some committee responses might have
    elif "title" in committee:
        name = committee["title"]
        
    # Option 5: Check for 'fullName' field
    elif "fullName" in committee:
        name = committee["fullName"]
        
    committee_type = committee.get("type", "Unknown")
    result.append(f"## {name}")
    result.append(f"Chamber: {chamber.capitalize()}")
    result.append(f"Committee Code: {committee_code}")
    result.append(f"Type: {committee_type}")
    
    # Add update date if available
    if "updateDate" in committee:
        result.append(f"Last Updated: {committee['updateDate']}")
        
    # Add current status if available
    if "isCurrent" in committee:
        is_current = "Yes" if committee["isCurrent"] else "No"
        result.append(f"Current Committee: {is_current}")
    
    # Subcommittees
    if "subcommittees" in committee and committee["subcommittees"]:
        result.append("\n### Subcommittees:")
        for subcommittee in committee["subcommittees"]:
            sub_name = subcommittee.get("name", "Unknown")
            sub_code = subcommittee.get("systemCode", "Unknown")
            result.append(f"- {sub_name} ({sub_code})")
    
    # URL
    if "url" in committee:
        result.append(f"\nURL: {committee['url']}")
    
    return "\n".join(result)

# Tools (Interactive/Parameterized Functions)
# - get_committee_bills: Bills with limit parameter
# - get_committee_reports: Reports with limit parameter
# - get_committee_nominations: Nominations with limit parameter  
# - get_committee_communications: Communications with limit parameter
# - search_committees: Search functionality

async def get_committee_bills(
    ctx: Context,
    chamber: str,
    committee_code: str,
    limit: int = 10
) -> str:
    """
    Get bills referred to a specific committee.
    
    Args:
        chamber: The chamber of Congress ("house" or "senate")
        committee_code: The committee code (e.g., "hsag", "ssap")
        limit: Maximum number of bills to return (default: 10)
    """
    try:
        # Validate parameters
        chamber_validation = ParameterValidator.validate_chamber(chamber)
        if not chamber_validation.is_valid:
            logger.warning(f"Invalid chamber: {chamber}")
            return chamber_validation.error_message
            
        limit_validation = ParameterValidator.validate_limit_range(limit)
        if not limit_validation.is_valid:
            logger.warning(f"Invalid limit: {limit}")
            return limit_validation.error_message
        
        # Build endpoint
        endpoint = f"/committee/{chamber.lower()}/{committee_code}/bills"
        
        # Make API request
        response = await safe_committees_request(endpoint, ctx, {"limit": limit})
        
        if "error" in response:
            logger.warning(f"API error for committee bills: {response['error']}")
            return response["error"]
        
        bills = response.get("bills", [])
        if not bills:
            return f"No bills found for committee {committee_code} in the {chamber.capitalize()}."
        
        # Deduplicate bills
        bills = ResponseProcessor.deduplicate_results(
            bills, 
            key_fields=["congress", "number", "type"]
        )
        
        # Format results
        result = [f"Bills referred to {chamber.capitalize()} Committee {committee_code}:"]
        for bill in bills[:limit]:
            title = bill.get("title", "No title available")
            bill_type = bill.get("type", "Unknown")
            number = bill.get("number", "Unknown")
            congress = bill.get("congress", "Unknown")
            url = bill.get("url", "No URL available")
            
            # Get latest action
            latest_action = bill.get("latestAction", {})
            action_date = latest_action.get("actionDate", "Unknown")
            action_text = latest_action.get("text", "No action text")
            
            result.append(f"\n**{bill_type.upper()} {number}** (Congress {congress})")
            result.append(f"Title: {title}")
            result.append(f"Latest Action ({action_date}): {action_text}")
            result.append(f"URL: {url}")
        
        logger.info(f"Successfully retrieved {len(bills)} bills for committee {committee_code}")
        return "\n".join(result)
        
    except Exception as e:
        logger.error(f"Error in get_committee_bills: {str(e)}")
        error_response = CommonErrors.api_server_error("committee bills")
        error_response.details = {"error": str(e)}
        return format_error_response(error_response)

async def get_committee_reports(
    ctx: Context,
    chamber: str,
    committee_code: str,
    limit: int = 10
) -> str:
    """
    Get reports for a specific committee.
    
    Args:
        chamber: The chamber of Congress ("house" or "senate")
        committee_code: The committee code (e.g., "hspw00", "ssas00")
        limit: Maximum number of reports to return (default: 10)
    """
    try:
        # Validate parameters
        chamber_validation = ParameterValidator.validate_chamber(chamber)
        if not chamber_validation.is_valid:
            logger.warning(f"Invalid chamber: {chamber}")
            return chamber_validation.error_message
            
        limit_validation = ParameterValidator.validate_limit_range(limit)
        if not limit_validation.is_valid:
            logger.warning(f"Invalid limit: {limit}")
            return limit_validation.error_message
        
        # Build endpoint
        endpoint = f"/committee/{chamber.lower()}/{committee_code}/reports"
        
        # Make API request
        response = await safe_committees_request(endpoint, ctx, {"limit": limit})
        
        if "error" in response:
            logger.warning(f"API error for committee reports: {response['error']}")
            return response["error"]
        
        reports = response.get("reports", [])
        if not reports:
            return f"No reports found for committee {committee_code} in the {chamber.capitalize()}."
        
        # Deduplicate reports
        reports = ResponseProcessor.deduplicate_results(
            reports, 
            key_fields=["congress", "number", "type"]
        )
        
        # Format results
        result = [f"Reports from {chamber.capitalize()} Committee {committee_code}:"]
        for report in reports[:limit]:
            title = report.get("title", "No title available")
            report_type = report.get("type", "Unknown")
            number = report.get("number", "Unknown")
            congress = report.get("congress", "Unknown")
            url = report.get("url", "No URL available")
            update_date = report.get("updateDate", "Unknown")
            
            result.append(f"\n**{report_type.upper()} {number}** (Congress {congress})")
            result.append(f"Title: {title}")
            result.append(f"Updated: {update_date}")
            result.append(f"URL: {url}")
        
        logger.info(f"Successfully retrieved {len(reports)} reports for committee {committee_code}")
        return "\n".join(result)
        
    except Exception as e:
        logger.error(f"Error in get_committee_reports: {str(e)}")
        error_response = CommonErrors.api_server_error("committee reports")
        error_response.details = {"error": str(e)}
        return format_error_response(error_response)

async def get_committee_nominations(
    ctx: Context,
    committee_code: str,
    limit: int = 10
) -> str:
    """
    Get nominations for a specific Senate committee.
    
    Args:
        committee_code: The committee code (e.g., "ssas00")
        limit: Maximum number of nominations to return (default: 10)
    """
    try:
        # Validate parameters
        limit_validation = ParameterValidator.validate_limit_range(limit)
        if not limit_validation.is_valid:
            logger.warning(f"Invalid limit: {limit}")
            return limit_validation.error_message
        
        # Build endpoint (nominations are Senate-only)
        endpoint = f"/committee/senate/{committee_code}/nominations"
        
        # Make API request
        response = await safe_committees_request(endpoint, ctx, {"limit": limit})
        
        if "error" in response:
            logger.warning(f"API error for committee nominations: {response['error']}")
            return response["error"]
        
        nominations = response.get("nominations", [])
        if not nominations:
            return f"No nominations found for Senate committee {committee_code}."
        
        # Deduplicate nominations
        nominations = ResponseProcessor.deduplicate_results(
            nominations, 
            key_fields=["congress", "number"]
        )
        
        # Format results
        result = [f"Nominations for Senate Committee {committee_code}:"]
        for nomination in nominations[:limit]:
            number = nomination.get("number", "Unknown")
            congress = nomination.get("congress", "Unknown")
            url = nomination.get("url", "No URL available")
            update_date = nomination.get("updateDate", "Unknown")
            
            # Get nominees
            nominees = nomination.get("nominees", [])
            nominee_names = []
            for nominee in nominees:
                first_name = nominee.get("firstName", "")
                last_name = nominee.get("lastName", "")
                full_name = f"{first_name} {last_name}".strip()
                if full_name:
                    nominee_names.append(full_name)
            
            nominee_text = ", ".join(nominee_names) if nominee_names else "Unknown nominees"
            
            result.append(f"\n**Nomination {number}** (Congress {congress})")
            result.append(f"Nominees: {nominee_text}")
            result.append(f"Updated: {update_date}")
            result.append(f"URL: {url}")
        
        logger.info(f"Successfully retrieved {len(nominations)} nominations for committee {committee_code}")
        return "\n".join(result)
        
    except Exception as e:
        logger.error(f"Error in get_committee_nominations: {str(e)}")
        error_response = CommonErrors.api_server_error("committee nominations")
        error_response.details = {"error": str(e)}
        return format_error_response(error_response)

async def get_committee_communications(
    ctx: Context,
    chamber: str,
    committee_code: str,
    limit: int = 10
) -> str:
    """
    Get communications for a specific committee.
    
    Args:
        chamber: The chamber of Congress ("house" or "senate")
        committee_code: The committee code (e.g., "hspw00", "ssas00")
        limit: Maximum number of communications to return (default: 10)
    """
    try:
        # Validate parameters
        chamber_validation = ParameterValidator.validate_chamber(chamber)
        if not chamber_validation.is_valid:
            logger.warning(f"Invalid chamber: {chamber}")
            return chamber_validation.error_message
            
        limit_validation = ParameterValidator.validate_limit_range(limit)
        if not limit_validation.is_valid:
            logger.warning(f"Invalid limit: {limit}")
            return limit_validation.error_message
        
        # Build endpoint
        endpoint = f"/committee/{chamber.lower()}/{committee_code}/communications"
        
        # Make API request
        response = await safe_committees_request(endpoint, ctx, {"limit": limit})
        
        if "error" in response:
            logger.warning(f"API error for committee communications: {response['error']}")
            return response["error"]
        
        communications = response.get("communications", [])
        if not communications:
            return f"No communications found for committee {committee_code} in the {chamber.capitalize()}."
        
        # Deduplicate communications
        communications = ResponseProcessor.deduplicate_results(
            communications, 
            key_fields=["congress", "number"]
        )
        
        # Format results
        result = [f"Communications for {chamber.capitalize()} Committee {committee_code}:"]
        for comm in communications[:limit]:
            number = comm.get("number", "Unknown")
            congress = comm.get("congress", "Unknown")
            url = comm.get("url", "No URL available")
            
            # Get communication type
            comm_type = comm.get("communicationType", {})
            type_name = comm_type.get("name", "Unknown")
            
            # Get committee referral info
            committees = comm.get("committees", [])
            referral_date = "Unknown"
            if committees:
                referral_date = committees[0].get("referralDate", "Unknown")
            
            result.append(f"\n**{type_name} {number}** (Congress {congress})")
            result.append(f"Referral Date: {referral_date}")
            result.append(f"URL: {url}")
        
        logger.info(f"Successfully retrieved {len(communications)} communications for committee {committee_code}")
        return "\n".join(result)
        
    except Exception as e:
        logger.error(f"Error in get_committee_communications: {str(e)}")
        error_response = CommonErrors.api_server_error("committee communications")
        error_response.details = {"error": str(e)}
        return format_error_response(error_response)

async def search_committees(
    ctx: Context,
    keywords: str,
    chamber: Optional[str] = None,
    congress: Optional[int] = None,
    limit: int = 10
) -> str:
    """
    Search for committees based on keywords.
    
    Args:
        keywords: Keywords to search for in committee information
        chamber: Optional chamber of Congress ("house", "senate", or "joint")
        congress: Optional Congress number (e.g., 117)
        limit: Maximum number of results to return (default: 10)
    """
    try:
        # Validate parameters
        if chamber and chamber.lower() not in ["house", "senate", "joint"]:
            logger.warning(f"Invalid chamber: {chamber}")
            return f"Invalid chamber '{chamber}'. Must be 'house', 'senate', or 'joint'."
            
        if congress:
            congress_validation = ParameterValidator.validate_congress_number(congress)
            if not congress_validation.is_valid:
                logger.warning(f"Invalid congress number: {congress}")
                return congress_validation.error_message
                
        limit_validation = ParameterValidator.validate_limit_range(limit)
        if not limit_validation.is_valid:
            logger.warning(f"Invalid limit: {limit}")
            return limit_validation.error_message
        
        # Build search parameters
        params = {"q": keywords, "limit": limit}
        if chamber:
            params["chamber"] = chamber.lower()
        if congress:
            params["congress"] = congress
        
        # Make API request
        response = await safe_committees_request("/committee", ctx, params)
        
        if "error" in response:
            logger.warning(f"API error for committee search: {response['error']}")
            return response["error"]
        
        committees = response.get("committees", [])
        if not committees:
            return f"No committees found matching '{keywords}'."
        
        # Format results
        result = [f"Committees matching '{keywords}':"]
        for committee in committees[:limit]:
            result.append("\n" + format_committee_summary(committee))
        
        logger.info(f"Successfully found {len(committees)} committees for search '{keywords}'")
        return "\n".join(result)
        
    except Exception as e:
        logger.error(f"Error in search_committees: {str(e)}")
        error_response = CommonErrors.api_server_error("committee search")
        error_response.details = {"error": str(e)}
        return format_error_response(error_response)

async def get_committee_communication_details(
    ctx: Context,
    congress: int,
    chamber: str,
    communication_type: str,
    communication_number: int
) -> str:
    """
    Get detailed information about a specific committee communication.
    
    Args:
        congress: Congress number (e.g., 117 for 117th Congress)
        chamber: Chamber of Congress ("house" or "senate")
        communication_type: Communication type (e.g., "ec", "pm", "pom")
        communication_number: Communication number
        
    Returns:
        Detailed information about the specified communication
    """
    try:
        # Validate parameters
        congress_validation = ParameterValidator.validate_congress_number(congress)
        if not congress_validation.is_valid:
            logger.warning(f"Invalid congress number: {congress}")
            return congress_validation.error_message
            
        chamber_validation = ParameterValidator.validate_chamber(chamber)
        if not chamber_validation.is_valid:
            logger.warning(f"Invalid chamber: {chamber}")
            return chamber_validation.error_message
            
        # Validate communication type
        valid_comm_types = ["ec", "pm", "pom", "ml", "pt"]
        if communication_type.lower() not in valid_comm_types:
            logger.warning(f"Invalid communication type: {communication_type}")
            return f"Invalid communication type '{communication_type}'. Valid types: {', '.join(valid_comm_types)}"
            
        # Validate communication number
        if communication_number <= 0:
            logger.warning(f"Invalid communication number: {communication_number}")
            return "Communication number must be a positive integer"
            
        # Build endpoint based on chamber
        if chamber.lower() == "house":
            endpoint = f"/house-communication/{congress}/{communication_type.lower()}/{communication_number}"
        elif chamber.lower() == "senate":
            endpoint = f"/senate-communication/{congress}/{communication_type.lower()}/{communication_number}"
        else:
            return f"Invalid chamber '{chamber}'. Must be 'house' or 'senate'"
            
        logger.info(f"Fetching communication details: {endpoint}")
        
        # Make API request directly (like house_communications.py)
        response = await make_api_request(endpoint, ctx, {})
        
        # Log the entire response structure for debugging
        logger.debug(f"API response structure: {list(response.keys()) if isinstance(response, dict) else 'Not a dictionary'}")
        
        if "error" in response:
            logger.warning(f"API error for communication details: {response['error']}")
            return response["error"]
            
        # Debug: Log the response structure
        logger.debug(f"Response keys: {list(response.keys())}")
        logger.debug(f"Full response: {response}")
            
        # Extract communication data based on chamber - check for different possible response formats
        if chamber.lower() == "house":
            if 'house-communication' in response:
                communication_data = response['house-communication']
            elif 'houseCommunication' in response:
                communication_data = response['houseCommunication']
            else:
                logger.warning(f"Unexpected House response format. Keys: {list(response.keys()) if isinstance(response, dict) else 'Not a dictionary'}")
                return f"Retrieved house communication but in unexpected format. Keys: {list(response.keys())}"
        else:
            if 'senateCommunication' in response:
                communication_data = response['senateCommunication']
            elif 'senate-communication' in response:
                communication_data = response['senate-communication']
            else:
                logger.warning(f"Unexpected Senate response format. Keys: {list(response.keys()) if isinstance(response, dict) else 'Not a dictionary'}")
                return f"Retrieved senate communication but in unexpected format. Keys: {list(response.keys())}"
        
        # Format detailed communication information
        result = format_communication_details(communication_data, chamber)
        
        logger.info(f"Successfully retrieved communication details for {chamber} {communication_type} {communication_number}")
        return result
        
    except Exception as e:
        logger.error(f"Error in get_committee_communication_details: {str(e)}")
        error_response = CommonErrors.api_server_error("communication details")
        error_response.details = {"error": str(e)}
        return format_error_response(error_response)


def format_communication_details(communication: Dict[str, Any], chamber: str) -> str:
    """Format detailed communication information for display."""
    lines = [
        f"# {chamber.title()} Communication Details",
        f"",
        f"**Number**: {communication.get('number', 'N/A')}",
        f"**Congress**: {communication.get('congress', communication.get('congressNumber', 'N/A'))}",
        f"**Chamber**: {communication.get('chamber', chamber.title())}",
        f"**Session**: {communication.get('sessionNumber', 'N/A')}",
        f"**Congressional Record Date**: {communication.get('congressionalRecordDate', 'N/A')}",
        f"**Update Date**: {communication.get('updateDate', 'N/A')}",
        f""
    ]
    
    # Communication type
    comm_type = communication.get('communicationType', {})
    if comm_type:
        lines.extend([
            f"**Communication Type**: {comm_type.get('name', 'N/A')} ({comm_type.get('code', 'N/A')})",
            f""
        ])
    
    # Abstract/Description
    abstract = communication.get('abstract', '')
    if abstract:
        lines.extend([
            f"**Abstract**:",
            f"{abstract}",
            f""
        ])
    
    # Submitting information (House communications)
    if chamber.lower() == "house":
        submitting_agency = communication.get('submittingAgency', '')
        submitting_official = communication.get('submittingOfficial', '')
        if submitting_agency or submitting_official:
            lines.extend([
                f"**Submitting Information**:",
                f"  - Agency: {submitting_agency or 'N/A'}",
                f"  - Official: {submitting_official or 'N/A'}",
                f""
            ])
        
        # Report nature
        report_nature = communication.get('reportNature', '')
        if report_nature:
            lines.extend([
                f"**Report Nature**: {report_nature}",
                f""
            ])
        
        # Legal authority
        legal_authority = communication.get('legalAuthority', '')
        if legal_authority:
            lines.extend([
                f"**Legal Authority**: {legal_authority}",
                f""
            ])
        
        # Rulemaking
        is_rulemaking = communication.get('isRulemaking', '')
        if is_rulemaking:
            lines.extend([
                f"**Is Rulemaking**: {is_rulemaking}",
                f""
            ])
    
    # Committee referrals
    committees = communication.get('committees', [])
    if committees:
        lines.extend([
            f"**Committee Referrals**:"
        ])
        for committee in committees:
            lines.extend([
                f"  - **{committee.get('name', 'N/A')}** ({committee.get('systemCode', 'N/A')})",
                f"    - Referral Date: {committee.get('referralDate', 'N/A')}",
                f"    - URL: {committee.get('url', 'N/A')}"
            ])
        lines.append("")
    
    # Matching requirements (House communications)
    if chamber.lower() == "house":
        requirements = communication.get('matchingRequirements', [])
        if requirements:
            lines.extend([
                f"**Matching Requirements**:"
            ])
            for req in requirements:
                lines.append(f"  - {req.get('name', 'N/A')}")
            lines.append("")
    
    return "\n".join(lines)
