# summaries.py
from typing import Dict, Any, Optional, List
import json
import logging
from mcp.server.fastmcp import Context
from ..mcp_app import mcp
from ..core.client_handler import make_api_request

# Reliability Framework Imports
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 SummariesProcessor, clean_summaries_response

# Configure logging
logger = logging.getLogger(__name__)

# Formatting helpers
def format_summary(summary: Dict[str, Any]) -> str:
    """Format a summary into a readable format."""
    result = []
    
    # Basic information about the bill
    bill = summary.get("bill", {})
    bill_type = bill.get("type", "Unknown")
    bill_number = bill.get("number", "Unknown")
    congress = bill.get("congress", "Unknown")
    title = bill.get("title", "Untitled")
    
    result.append(f"# {title}")
    result.append(f"**Bill:** {bill_type.upper()} {bill_number} ({congress}th Congress)")
    
    # Action information
    action_date = summary.get("actionDate", "Unknown date")
    action_desc = summary.get("actionDesc", "Unknown action")
    result.append(f"**Action:** {action_desc} on {action_date}")
    
    # Chamber information
    current_chamber = summary.get("currentChamber", "Unknown")
    result.append(f"**Current Chamber:** {current_chamber}")
    
    # Summary text
    if "text" in summary:
        result.append("\n## Summary")
        result.append(summary["text"])
    
    # Update information
    update_date = summary.get("updateDate", "Unknown")
    result.append(f"\n**Last Updated:** {update_date}")
    
    return "\n".join(result)

def format_summaries_list(summaries: List[Dict[str, Any]], title: str) -> str:
    """Format a list of summaries into a readable format."""
    if not summaries:
        return "No summaries found."
    
    result = [f"# {title}\n"]
    result.append(f"**Found {len(summaries)} summaries**\n")
    
    for i, summary in enumerate(summaries, 1):
        result.append(f"## {i}. Summary")
        
        # Basic information about the bill
        bill = summary.get("bill", {})
        bill_type = bill.get("type", "Unknown")
        bill_number = bill.get("number", "Unknown")
        congress = bill.get("congress", "Unknown")
        title = bill.get("title", "Untitled")
        
        result.append(f"**Bill:** {bill_type.upper()} {bill_number} ({congress}th Congress)")
        result.append(f"**Title:** {title}")
        
        # Action information
        action_date = summary.get("actionDate", "Unknown date")
        action_desc = summary.get("actionDesc", "Unknown action")
        result.append(f"**Action:** {action_desc} on {action_date}")
        
        # Update information
        update_date = summary.get("updateDate", "Unknown")
        result.append(f"**Last Updated:** {update_date}")
        
        # Add URL to view full summary
        bill_url = bill.get("url", "")
        if bill_url:
            result.append(f"\n[View Bill Details]({bill_url})")
        
        result.append("")  # Add spacing between summaries
    
    return "\n".join(result)

# Resources
@mcp.resource("congress://summaries/latest")
async def get_latest_summaries(ctx: Context) -> str:
    """
    Get the most recent bill summaries.
    
    Returns a list of the 10 most recently updated summaries across all
    Congresses, sorted by update date in descending order.
    """
    logger.info("Accessing latest summaries resource")
    try:
        # Use defensive API wrapper
        data = await safe_congressional_request("/summaries", ctx, {"limit": 10, "sort": "updateDate+desc"}, endpoint_type='summaries')
        logger.info(f"API response received: {data.keys() if isinstance(data, dict) else 'not a dict'}")  
        
        if "error" in data:
            logger.error(f"Error in API response: {data['error']}")
            return format_error_response(
                CommonErrors.api_server_error("/summaries", data["error"])
            )
        
        # Process response with deduplication and cleaning
        summaries = clean_summaries_response(data, limit=10)
        
        if not summaries:
            return "No recent summaries found."
        
        logger.info(f"Returning {len(summaries)} latest summaries")
        return format_summaries_list(summaries, "Latest Bill Summaries")
        
    except Exception as e:
        logger.error(f"Error accessing latest summaries: {str(e)}")
        return format_error_response(
            CommonErrors.api_server_error("/summaries", str(e))
        )

@mcp.resource("congress://summaries/{congress}")
async def get_summaries_by_congress(ctx: Context, congress: str) -> str:
    """
    Get summaries from a specific Congress.
    
    Args:
        congress: The number of the Congress (e.g., "117")
        
    Returns a list of the 10 most recently updated summaries from the
    specified Congress, sorted by update date in descending order.
    """
    logger.info(f"Accessing summaries for Congress {congress}")
    
    try:
        # Validate congress parameter
        congress_int = int(congress)
        validation = ParameterValidator.validate_congress_number(congress_int)
        if not validation.is_valid:
            return format_error_response(
                CommonErrors.invalid_parameter("congress", congress, validation.error_message, validation.suggestions)
            )
        
        # Use defensive API wrapper
        data = await safe_congressional_request(f"/summaries/{congress}", ctx, {"limit": 10, "sort": "updateDate+desc"}, endpoint_type='summaries')
        
        if "error" in data:
            logger.error(f"Error in API response: {data['error']}")
            return format_error_response(
                CommonErrors.api_server_error(f"/summaries/{congress}", data["error"])
            )
        
        # Process response with deduplication and cleaning
        summaries = clean_summaries_response(data, limit=10)
        
        if not summaries:
            return f"No summaries found for the {congress}th Congress."
        
        logger.info(f"Returning {len(summaries)} summaries for Congress {congress}")
        return format_summaries_list(summaries, f"Bill Summaries - {congress}th Congress")
        
    except ValueError:
        return format_error_response(
            CommonErrors.invalid_parameter("congress", congress, "Congress must be a valid number", ["117", "118", "119"])
        )
    except Exception as e:
        logger.error(f"Error accessing summaries for Congress {congress}: {str(e)}")
        return format_error_response(
            CommonErrors.api_server_error(f"/summaries/{congress}", str(e))
        )

@mcp.resource("congress://summaries/{congress}/{bill_type}")
async def get_summaries_by_type(ctx: Context, congress: str, bill_type: str) -> str:
    """
    Get summaries from a specific Congress and bill type.
    
    Args:
        congress: The number of the Congress (e.g., "117")
        bill_type: The type of bill (e.g., "hr", "s")
        
    Returns a list of the 10 most recently updated summaries of the specified
    bill type from the specified Congress, sorted by update date in descending order.
    """
    logger.info(f"Accessing summaries for Congress {congress}, bill type {bill_type}")
    
    try:
        # Validate congress parameter
        congress_int = int(congress)
        validation = ParameterValidator.validate_congress_number(congress_int)
        if not validation.is_valid:
            return format_error_response(
                CommonErrors.invalid_parameter("congress", congress, validation.error_message, validation.suggestions)
            )
        
        # Validate bill type
        bill_validation = ParameterValidator.validate_bill_type(bill_type)
        if not bill_validation.is_valid:
            return format_error_response(
                CommonErrors.invalid_parameter("bill_type", bill_type, bill_validation.error_message, bill_validation.suggestions)
            )
        
        # Use defensive API wrapper
        data = await safe_congressional_request(f"/summaries/{congress}/{bill_type}", ctx, {"limit": 10, "sort": "updateDate+desc"}, endpoint_type='summaries')
        
        if "error" in data:
            logger.error(f"Error in API response: {data['error']}")
            return format_error_response(
                CommonErrors.api_server_error(f"/summaries/{congress}/{bill_type}", data["error"])
            )
        
        # Process response with deduplication and cleaning
        summaries = clean_summaries_response(data, limit=10)
        
        if not summaries:
            return f"No {bill_type.upper()} summaries found for the {congress}th Congress."
        
        logger.info(f"Returning {len(summaries)} {bill_type.upper()} summaries for Congress {congress}")
        return format_summaries_list(summaries, f"{bill_type.upper()} Bill Summaries - {congress}th Congress")
        
    except ValueError:
        return format_error_response(
            CommonErrors.invalid_parameter("congress", congress, "Congress must be a valid number", ["117", "118", "119"])
        )
    except Exception as e:
        logger.error(f"Error accessing summaries for Congress {congress}, bill type {bill_type}: {str(e)}")
        return format_error_response(
            CommonErrors.api_server_error(f"/summaries/{congress}/{bill_type}", str(e))
        )

@mcp.resource("congress://summaries/help")
async def get_summaries_help(ctx: Context) -> str:
    """
    Get usage guide and examples for the summaries API.
    
    Returns comprehensive information about how to use summaries endpoints,
    including examples, parameter formats, and best practices.
    """
    return """# 📋 **Bill Summaries API - Usage Guide**

## **Available Resources**

### **📊 Latest Summaries**
- **Resource**: `congress://summaries/latest`
- **Description**: Get the 10 most recent bill summaries across all Congresses
- **Use Case**: Stay updated on recent legislative activity

### **🏛️ Congress-Specific Summaries**  
- **Resource**: `congress://summaries/{congress}`
- **Description**: Get summaries from a specific Congress (e.g., 118th Congress)
- **Example**: `congress://summaries/118`
- **Use Case**: Research legislative activity in a particular Congress

### **📝 Bill Type Summaries**
- **Resource**: `congress://summaries/{congress}/{bill_type}`
- **Description**: Get summaries for specific bill types in a Congress
- **Example**: `congress://summaries/118/hr` (House bills in 118th Congress)
- **Use Case**: Focus on specific types of legislation

## **Available Tools**

### **🔍 Search Summaries**
- **Tool**: `search_summaries`
- **Parameters**: keywords, congress (optional), bill_type (optional), limit, sort, from_date, to_date
- **Example**: Search for "climate change" summaries in 118th Congress
- **Use Case**: Find summaries by topic or keyword

### **📄 Specific Bill Summaries**
- **Tool**: `get_bill_summaries`  
- **Parameters**: congress, bill_type, bill_number
- **Example**: Get summaries for HR 1 in 118th Congress
- **Use Case**: Get all summaries for a specific bill

## **Valid Bill Types**
- **hr** - House Bill
- **s** - Senate Bill  
- **hjres** - House Joint Resolution
- **sjres** - Senate Joint Resolution
- **hconres** - House Concurrent Resolution
- **sconres** - Senate Concurrent Resolution
- **hres** - House Resolution
- **sres** - Senate Resolution

## **Congress Number Ranges**
- **Valid Range**: 1-119 (1st Congress to current)
- **Current Congress**: 119th (2025-2027)
- **Recent Congresses**: 118th (2023-2025), 117th (2021-2023), 116th (2019-2021)

## **Date Format**
- **Format**: ISO 8601 (YYYY-MM-DDTHH:MM:SSZ)
- **Example**: `2024-01-01T00:00:00Z`

## **Limits**
- **Search Results**: 1-250 (default: 10)
- **API Rate Limits**: Managed automatically with retry logic

## **Examples**

### **Find Climate Legislation**
```
Tool: search_summaries
Keywords: "climate change"
Congress: 118
Bill Type: hr
Limit: 20
```

### **Get Infrastructure Bill Summaries**
```
Tool: get_bill_summaries
Congress: 117
Bill Type: hr
Bill Number: 3684
```

### **Latest Senate Resolutions**
```
Resource: congress://summaries/118/sres
```

## **Tips for Best Results**
- Use specific keywords for better search results
- Combine congress and bill_type filters to narrow results
- Check multiple Congresses for comprehensive research
- Use date ranges to focus on specific time periods
"""

@mcp.resource("congress://summaries/api-info")
async def get_summaries_api_info(ctx: Context) -> str:
    """
    Get technical information about the summaries API including limits and capabilities.
    
    Returns information about API endpoints, rate limits, response formats,
    and technical specifications for developers.
    """
    return """# 🔧 **Summaries API - Technical Information**

## **API Endpoints**

### **Base Endpoint**
- **URL**: `/summaries`
- **Method**: GET
- **Authentication**: Managed automatically

### **Endpoint Variations**
- `/summaries` - All summaries with pagination
- `/summaries/{congress}` - Congress-specific summaries  
- `/summaries/{congress}/{bill_type}` - Bill type specific summaries

## **Rate Limits & Performance**

### **Request Limits**
- **Timeout**: 10 seconds per request
- **Retries**: 2 automatic retries on failure
- **Retry Delay**: 1 second between retries
- **Max Results**: 250 per request

### **Response Processing**
- **Deduplication**: Automatic removal of duplicate summaries
- **Sorting**: By update date (newest first)
- **Filtering**: Client-side keyword filtering for search

## **Response Format**

### **Successful Response Structure**
```json
{
  "summaries": [
    {
      "congress": 118,
      "bill": {
        "type": "hr",
        "number": 1234,
        "title": "Bill Title"
      },
      "summaryText": "Summary content...",
      "actionDate": "2024-01-15",
      "updateDate": "2024-01-15T10:30:00Z"
    }
  ],
  "pagination": {
    "count": 25,
    "next": "next_page_url"
  }
}
```

### **Error Response Structure**
```json
{
  "error": "Error message",
  "details": "Detailed error information",
  "suggestions": ["Helpful suggestion 1", "Helpful suggestion 2"]
}
```

## **Parameter Validation**

### **Congress Numbers**
- **Range**: 1-119
- **Type**: Integer
- **Validation**: Automatic range checking

### **Bill Types**
- **Valid Values**: hr, s, hjres, sjres, hconres, sconres, hres, sres
- **Case**: Insensitive (automatically converted to lowercase)
- **Validation**: Automatic format checking

### **Bill Numbers**
- **Range**: 1-99999
- **Type**: Positive integer
- **Validation**: Automatic range and type checking

### **Dates**
- **Format**: ISO 8601 (YYYY-MM-DDTHH:MM:SSZ)
- **Timezone**: UTC (Z suffix required)
- **Validation**: Automatic format verification

## **Error Handling**

### **Common Error Types**
- **Invalid Parameters**: User-friendly messages with suggestions
- **API Timeouts**: Automatic retry with exponential backoff
- **Server Errors**: Graceful degradation with helpful error messages
- **Rate Limiting**: Automatic handling with retry logic

### **Defensive Programming**
- **Timeout Protection**: Prevents hanging requests
- **Input Sanitization**: Automatic parameter cleaning
- **Response Validation**: Ensures data integrity
- **Comprehensive Logging**: Enhanced debugging capabilities

## **Data Quality Features**

### **Deduplication Logic**
- **Key Fields**: Congress + Bill Type + Bill Number + Action Date
- **Algorithm**: Hash-based duplicate detection
- **Result**: Clean, unique summaries only

### **Sorting & Filtering**
- **Default Sort**: Update date (newest first)
- **Search Filtering**: Title, text, and action description
- **Case Insensitive**: All text searches ignore case
- **Partial Matching**: Supports substring matching

## **Integration Notes**

### **MCP Architecture**
- **Resources**: Static/hierarchical data (no parameters)
- **Tools**: Dynamic operations (require parameters)
- **Consistency**: Follows Congressional MCP patterns

### **Reliability Framework**
- **Defensive API Wrapper**: Timeout and retry protection
- **Parameter Validation**: Comprehensive input checking
- **Error Standardization**: Consistent error response format
- **Response Processing**: Automatic cleaning and deduplication
"""

# Tools
# @require_paid_access
async def search_summaries(
    ctx: Context,
    keywords: str, 
    congress: Optional[int] = None, 
    bill_type: Optional[str] = None,
    limit: int = 10,
    sort: str = "updateDate+desc",
    from_date: Optional[str] = None,
    to_date: Optional[str] = None
) -> str:
    """
    Search for bill summaries based on keywords.
    
    Args:
        keywords: Keywords to search for in bill summaries
        congress: Optional Congress number (e.g., 117 for 117th Congress)
        bill_type: Optional bill type (e.g., 'hr' for House Bill, 's' for Senate Bill)
        limit: Maximum number of results to return (default: 10)
        sort: Sort order (default: "updateDate+desc")
        from_date: Optional start date for filtering (format: YYYY-MM-DDT00:00:00Z)
        to_date: Optional end date for filtering (format: YYYY-MM-DDT00:00:00Z)
    """
    logger.info(f"Searching for summaries with keywords: {keywords}")
    
    try:
        # Parameter validation
        if not keywords or not keywords.strip():
            return format_error_response(
                CommonErrors.invalid_parameter("keywords", keywords, "Keywords cannot be empty", ["climate change", "healthcare", "defense"])
            )
        
        # Validate limit
        limit_validation = ParameterValidator.validate_limit_range(limit, 250)
        if not limit_validation.is_valid:
            return format_error_response(
                CommonErrors.invalid_parameter("limit", str(limit), limit_validation.error_message, limit_validation.suggestions)
            )
        
        # Validate congress if provided
        if congress is not None:
            congress_validation = ParameterValidator.validate_congress_number(congress)
            if not congress_validation.is_valid:
                return format_error_response(
                    CommonErrors.invalid_parameter("congress", str(congress), congress_validation.error_message, congress_validation.suggestions)
                )
        
        # Validate bill type if provided
        if bill_type is not None:
            bill_validation = ParameterValidator.validate_bill_type(bill_type)
            if not bill_validation.is_valid:
                return format_error_response(
                    CommonErrors.invalid_parameter("bill_type", bill_type, bill_validation.error_message, bill_validation.suggestions)
                )
        
        # Validate date formats if provided
        if from_date is not None:
            date_validation = ParameterValidator.validate_date_format(from_date)
            if not date_validation.is_valid:
                return format_error_response(
                    CommonErrors.invalid_parameter("from_date", from_date, date_validation.error_message, date_validation.suggestions)
                )
        
        if to_date is not None:
            date_validation = ParameterValidator.validate_date_format(to_date)
            if not date_validation.is_valid:
                return format_error_response(
                    CommonErrors.invalid_parameter("to_date", to_date, date_validation.error_message, date_validation.suggestions)
                )
        
        # Build API request parameters
        params = {
            # Increase the limit to get more results for filtering
            "limit": min(100, limit * 5),  # Get more results but cap at 100
            "sort": sort
        }
        
        # Add optional date filters if provided
        if from_date:
            params["fromDateTime"] = from_date
        if to_date:
            params["toDateTime"] = to_date
        
        # Build endpoint
        endpoint = "/summaries"
        if congress is not None:
            endpoint = f"/summaries/{congress}"
            if bill_type is not None:
                endpoint = f"/summaries/{congress}/{bill_type}"
        
        # Use defensive API wrapper
        data = await safe_congressional_request(endpoint, ctx, params, endpoint_type='summaries')
        
        if "error" in data:
            logger.error(f"Error in API response: {data['error']}")
            return format_error_response(
                CommonErrors.api_server_error(endpoint, data["error"])
            )
        
        # Process response with deduplication and cleaning
        summaries = clean_summaries_response(data, limit=100)  # Get more for filtering
        
        if not summaries:
            return f"No summaries found for the specified criteria."
        
        # Client-side filtering based on keywords using processor
        filtered_summaries = SummariesProcessor.filter_by_keywords(summaries, keywords)
        
        # Limit the results to the requested number
        filtered_summaries = filtered_summaries[:limit]
        
        if not filtered_summaries:
            return f"No summaries found matching '{keywords}'."
        
        logger.info(f"Found {len(filtered_summaries)} summaries matching '{keywords}'")
        return format_summaries_list(filtered_summaries, f"Bill Summaries Matching '{keywords}'")
        
    except Exception as e:
        logger.error(f"Error searching summaries with keywords '{keywords}': {str(e)}")
        return format_error_response(
            CommonErrors.api_server_error("/summaries", str(e))
        )


# @require_paid_access
async def get_bill_summaries(
    ctx: Context,
    congress: int,
    bill_type: str,
    bill_number: int
) -> str:
    """
    Get summaries for a specific bill.
    
    Args:
        congress: Congress number (e.g., 117 for 117th Congress)
        bill_type: Bill type (e.g., 'hr' for House Bill, 's' for Senate Bill)
        bill_number: Bill number
    """
    logger.info(f"Getting summaries for {bill_type.upper()} {bill_number} in Congress {congress}")
    
    try:
        # Parameter validation
        congress_validation = ParameterValidator.validate_congress_number(congress)
        if not congress_validation.is_valid:
            return format_error_response(
                CommonErrors.invalid_parameter("congress", str(congress), congress_validation.error_message, congress_validation.suggestions)
            )
        
        bill_validation = ParameterValidator.validate_bill_type(bill_type)
        if not bill_validation.is_valid:
            return format_error_response(
                CommonErrors.invalid_parameter("bill_type", bill_type, bill_validation.error_message, bill_validation.suggestions)
            )
        
        number_validation = ParameterValidator.validate_bill_number(bill_number)
        if not number_validation.is_valid:
            return format_error_response(
                CommonErrors.invalid_parameter("bill_number", str(bill_number), number_validation.error_message, number_validation.suggestions)
            )
        
        # Use the existing bill summaries endpoint with defensive wrapper
        endpoint = f"/bill/{congress}/{bill_type}/{bill_number}/summaries"
        data = await safe_congressional_request(endpoint, ctx, {}, endpoint_type='summaries')
        
        if "error" in data:
            logger.error(f"Error in API response: {data['error']}")
            return format_error_response(
                CommonErrors.api_server_error(endpoint, data["error"])
            )
        
        # Handle different data structures for summaries
        summaries_data = data.get("summaries", {})
        
        # Extract summary items based on the data structure
        if isinstance(summaries_data, list):
            summaries = summaries_data
        elif isinstance(summaries_data, dict) and "item" in summaries_data:
            items = summaries_data["item"]
            if isinstance(items, list):
                summaries = items
            else:
                # If there's only one item, wrap it in a list
                summaries = [items]
        else:
            # If we can't determine the structure, just use an empty list
            logger.warning(f"Unexpected summaries structure: {type(summaries_data)}")
            summaries = []
        
        if not summaries:
            return f"No summaries found for {bill_type.upper()} {bill_number} in the {congress}th Congress."
        
        # Deduplicate summaries
        summaries = SummariesProcessor.deduplicate_summaries(summaries)
        
        result = [f"# Summaries for {bill_type.upper()} {bill_number} - {congress}th Congress"]
        result.append(f"**Found {len(summaries)} summaries**\n")
        
        for i, summary in enumerate(summaries, 1):
            result.append(f"## {i}. Summary Version")
            
            # Get version code and date
            version_code = summary.get("versionCode", "Unknown")
            version_date = summary.get("updateDate", "Unknown date")
            
            result.append(f"**Version:** {version_code}")
            result.append(f"**Date:** {version_date}")
            
            # Get summary text
            if "text" in summary:
                result.append("\n### Content")
                result.append(summary["text"])
            
            result.append("")  # Add spacing between summaries
        
        logger.info(f"Returning {len(summaries)} summaries for {bill_type.upper()} {bill_number}")
        return "\n".join(result)
        
    except Exception as e:
        logger.error(f"Error getting summaries for {bill_type.upper()} {bill_number} in Congress {congress}: {str(e)}")
        return format_error_response(
            CommonErrors.api_server_error(f"/bill/{congress}/{bill_type}/{bill_number}/summaries", str(e))
        )
