"""
CPAP MCP Server - Exposes cpap-py library functionality via Model Context Protocol.

This server allows AI models to:
1. Upload CPAP data files (from SD card exports)
2. Parse and analyze the data
3. Access session details, waveforms, and events
4. Generate therapy recommendations
"""

import asyncio
import base64
import json
import os
import shutil
import tempfile
import zipfile
from datetime import date, datetime
from pathlib import Path
from typing import Any, Dict, List, Optional

from mcp.server import Server
from mcp.server.stdio import stdio_server
from mcp.types import Tool, TextContent, ImageContent, EmbeddedResource

# Import cpap-py library (from submodule)
import sys
sys.path.insert(0, str(Path(__file__).parent.parent.parent / "submodules" / "cpap-py" / "src"))

from cpap_py import CPAPReader, Device, Session, SettingsProposal
from cpap_py.models import EventType
from cpap_py.settings import (
    create_pressure_adjustment_proposal,
    create_comfort_improvement_proposal,
)

# Global state
app = Server("cpap-mcp")
working_dir: Optional[Path] = None
cpap_reader: Optional[CPAPReader] = None


def get_working_dir() -> Path:
    """Get or create the working directory for uploaded files."""
    global working_dir
    if working_dir is None:
        working_dir = Path(tempfile.mkdtemp(prefix="cpap_mcp_"))
    return working_dir


def initialize_reader() -> CPAPReader:
    """Initialize or return the CPAPReader instance."""
    global cpap_reader
    if cpap_reader is None:
        work_dir = get_working_dir()
        if not work_dir.exists():
            raise ValueError("Working directory not initialized. Upload files first.")
        cpap_reader = CPAPReader(str(work_dir))
    return cpap_reader


def reset_reader():
    """Reset the reader (e.g., after uploading new files)."""
    global cpap_reader
    cpap_reader = None


def serialize_datetime(obj: Any) -> Any:
    """Helper to serialize datetime objects."""
    if isinstance(obj, (datetime, date)):
        return obj.isoformat()
    return obj


@app.list_tools()
async def list_tools() -> List[Tool]:
    """List available tools for CPAP data analysis."""
    return [
        Tool(
            name="upload_archive",
            description=(
                "Upload a ZIP archive containing CPAP data files from the SD card. "
                "The ZIP should contain the SD card's directory structure (e.g., DATALOG/, STR.edf, etc.). "
                "This is more efficient than uploading individual files. "
                "Archive content should be base64 encoded."
            ),
            inputSchema={
                "type": "object",
                "properties": {
                    "content": {
                        "type": "string",
                        "description": "Base64 encoded ZIP archive content",
                    },
                },
                "required": ["content"],
            },
        ),
        Tool(
            name="list_uploaded_files",
            description="List all files that have been uploaded to the working directory.",
            inputSchema={
                "type": "object",
                "properties": {},
            },
        ),
        Tool(
            name="clear_uploaded_files",
            description="Clear all uploaded files and reset the working directory.",
            inputSchema={
                "type": "object",
                "properties": {},
            },
        ),
        Tool(
            name="get_devices",
            description=(
                "Get information about CPAP devices found in the uploaded data. "
                "Returns device serial numbers, model names, and firmware versions."
            ),
            inputSchema={
                "type": "object",
                "properties": {},
            },
        ),
        Tool(
            name="get_sessions",
            description=(
                "Get therapy sessions with optional filtering. Returns session dates, durations, "
                "AHI scores, leak data, pressure statistics, and more. Each session represents "
                "one night of CPAP therapy."
            ),
            inputSchema={
                "type": "object",
                "properties": {
                    "device_id": {
                        "type": "string",
                        "description": "Filter by device serial number (optional)",
                    },
                    "start_date": {
                        "type": "string",
                        "description": "Filter sessions on or after this date (ISO format: YYYY-MM-DD)",
                    },
                    "end_date": {
                        "type": "string",
                        "description": "Filter sessions on or before this date (ISO format: YYYY-MM-DD)",
                    },
                    "min_duration_hours": {
                        "type": "number",
                        "description": "Minimum session duration in hours",
                        "default": 0.0,
                    },
                },
            },
        ),
        Tool(
            name="get_session_details",
            description=(
                "Get detailed information about a specific session including summary statistics, "
                "device settings, and available data types."
            ),
            inputSchema={
                "type": "object",
                "properties": {
                    "session_id": {
                        "type": "string",
                        "description": "Session ID from get_sessions",
                    },
                },
                "required": ["session_id"],
            },
        ),
        Tool(
            name="get_session_events",
            description=(
                "Get respiratory and device events for a session. Returns apneas, hypopneas, "
                "flow limitations, mask on/off events, and more."
            ),
            inputSchema={
                "type": "object",
                "properties": {
                    "session_id": {
                        "type": "string",
                        "description": "Session ID from get_sessions",
                    },
                    "event_type": {
                        "type": "string",
                        "description": "Filter by event type (optional): OA, CA, H, FL, RE, VS, etc.",
                    },
                },
                "required": ["session_id"],
            },
        ),
        Tool(
            name="get_session_pressure_data",
            description=(
                "Get pressure waveform data for a session. Returns time-series pressure data "
                "that can be used for detailed analysis. Warning: May return large amounts of data."
            ),
            inputSchema={
                "type": "object",
                "properties": {
                    "session_id": {
                        "type": "string",
                        "description": "Session ID from get_sessions",
                    },
                    "sample_limit": {
                        "type": "integer",
                        "description": "Maximum number of samples to return (default: 1000)",
                        "default": 1000,
                    },
                },
                "required": ["session_id"],
            },
        ),
        Tool(
            name="get_session_flow_data",
            description=(
                "Get flow waveform data for a session. Returns time-series flow data. "
                "Warning: May return large amounts of data."
            ),
            inputSchema={
                "type": "object",
                "properties": {
                    "session_id": {
                        "type": "string",
                        "description": "Session ID from get_sessions",
                    },
                    "sample_limit": {
                        "type": "integer",
                        "description": "Maximum number of samples to return (default: 1000)",
                        "default": 1000,
                    },
                },
                "required": ["session_id"],
            },
        ),
        Tool(
            name="get_session_spo2_data",
            description=(
                "Get SpO2 (blood oxygen saturation) waveform data for a session. "
                "Returns time-series oximetry data if available."
            ),
            inputSchema={
                "type": "object",
                "properties": {
                    "session_id": {
                        "type": "string",
                        "description": "Session ID from get_sessions",
                    },
                    "sample_limit": {
                        "type": "integer",
                        "description": "Maximum number of samples to return (default: 1000)",
                        "default": 1000,
                    },
                },
                "required": ["session_id"],
            },
        ),
        Tool(
            name="get_summary_statistics",
            description=(
                "Get aggregate statistics across multiple sessions for a time period. "
                "Returns average AHI, total usage hours, compliance data, and more."
            ),
            inputSchema={
                "type": "object",
                "properties": {
                    "device_id": {
                        "type": "string",
                        "description": "Filter by device serial number (optional)",
                    },
                    "days": {
                        "type": "integer",
                        "description": "Number of recent days to include (default: 30)",
                        "default": 30,
                    },
                },
            },
        ),
        Tool(
            name="get_device_settings",
            description=(
                "Get current device settings including pressure modes, EPR settings, "
                "ramp configuration, and comfort features."
            ),
            inputSchema={
                "type": "object",
                "properties": {
                    "session_id": {
                        "type": "string",
                        "description": "Session ID to get settings from (uses most recent if not specified)",
                    },
                },
            },
        ),
        Tool(
            name="analyze_therapy_effectiveness",
            description=(
                "Analyze therapy effectiveness across sessions. Identifies trends in AHI, "
                "leak rates, usage patterns, and provides insights for optimization."
            ),
            inputSchema={
                "type": "object",
                "properties": {
                    "days": {
                        "type": "integer",
                        "description": "Number of recent days to analyze (default: 30)",
                        "default": 30,
                    },
                },
            },
        ),
        Tool(
            name="get_validation_errors",
            description=(
                "Get list of validation errors and warnings encountered during data parsing. "
                "Includes CRC validation failures, missing files, and parse errors."
            ),
            inputSchema={
                "type": "object",
                "properties": {},
            },
        ),
        Tool(
            name="export_all_data",
            description=(
                "Export all CPAP data (devices, sessions, validation errors) as a complete "
                "JSON-serializable dictionary. Useful for comprehensive data review."
            ),
            inputSchema={
                "type": "object",
                "properties": {},
            },
        ),
        Tool(
            name="propose_pressure_adjustment",
            description=(
                "Generate a settings proposal to adjust therapy pressure based on AHI and other "
                "metrics. Includes safety validation and expected outcomes. Does NOT modify device."
            ),
            inputSchema={
                "type": "object",
                "properties": {
                    "target_pressure": {
                        "type": "number",
                        "description": "Target pressure in cmH2O (for CPAP) or max pressure (for APAP)",
                    },
                    "reason": {
                        "type": "string",
                        "description": "Reason for the pressure adjustment",
                    },
                    "session_id": {
                        "type": "string",
                        "description": "Session ID to get current settings from (uses most recent if not specified)",
                    },
                },
                "required": ["target_pressure", "reason"],
            },
        ),
        Tool(
            name="propose_comfort_improvements",
            description=(
                "Generate a settings proposal to improve therapy comfort (EPR, ramp, etc.). "
                "Includes safety validation and expected outcomes. Does NOT modify device."
            ),
            inputSchema={
                "type": "object",
                "properties": {
                    "enable_epr": {
                        "type": "boolean",
                        "description": "Enable Expiratory Pressure Relief",
                        "default": True,
                    },
                    "epr_level": {
                        "type": "integer",
                        "description": "EPR level 0-3 (0=off, 3=maximum relief)",
                        "default": 2,
                    },
                    "enable_ramp": {
                        "type": "boolean",
                        "description": "Enable pressure ramp",
                        "default": True,
                    },
                    "ramp_time": {
                        "type": "integer",
                        "description": "Ramp time in minutes",
                        "default": 20,
                    },
                    "session_id": {
                        "type": "string",
                        "description": "Session ID to get current settings from (uses most recent if not specified)",
                    },
                },
            },
        ),
    ]


@app.call_tool()
async def call_tool(name: str, arguments: Any) -> List[TextContent]:
    """Handle tool calls."""
    
    try:
        if name == "upload_archive":
            return await upload_archive(arguments)
        elif name == "list_uploaded_files":
            return await list_uploaded_files()
        elif name == "clear_uploaded_files":
            return await clear_uploaded_files()
        elif name == "get_devices":
            return await get_devices()
        elif name == "get_sessions":
            return await get_sessions(arguments)
        elif name == "get_session_details":
            return await get_session_details(arguments)
        elif name == "get_session_events":
            return await get_session_events(arguments)
        elif name == "get_session_pressure_data":
            return await get_session_pressure_data(arguments)
        elif name == "get_session_flow_data":
            return await get_session_flow_data(arguments)
        elif name == "get_session_spo2_data":
            return await get_session_spo2_data(arguments)
        elif name == "get_summary_statistics":
            return await get_summary_statistics(arguments)
        elif name == "get_device_settings":
            return await get_device_settings(arguments)
        elif name == "analyze_therapy_effectiveness":
            return await analyze_therapy_effectiveness(arguments)
        elif name == "get_validation_errors":
            return await get_validation_errors()
        elif name == "export_all_data":
            return await export_all_data()
        elif name == "propose_pressure_adjustment":
            return await propose_pressure_adjustment(arguments)
        elif name == "propose_comfort_improvements":
            return await propose_comfort_improvements(arguments)
        else:
            raise ValueError(f"Unknown tool: {name}")
    except Exception as e:
        return [TextContent(type="text", text=f"Error: {str(e)}")]


async def upload_archive(arguments: Dict[str, Any]) -> List[TextContent]:
    """Upload and extract a ZIP archive to the working directory."""
    content_b64 = arguments.get("content")
    
    if not content_b64:
        raise ValueError("content is required")
    
    # Decode base64 content
    try:
        content = base64.b64decode(content_b64)
    except Exception as e:
        raise ValueError(f"Failed to decode base64 content: {e}")
    
    # Verify it's a valid ZIP file
    try:
        # Create a temporary file for the ZIP
        work_dir = get_working_dir()
        temp_zip = work_dir / "temp_upload.zip"
        temp_zip.write_bytes(content)
        
        # Extract the ZIP
        extracted_files = []
        with zipfile.ZipFile(temp_zip, 'r') as zip_ref:
            # Get list of files
            file_list = zip_ref.namelist()
            
            # Extract all files
            for file_name in file_list:
                # Skip directories and hidden files
                if file_name.endswith('/') or file_name.startswith('.'):
                    continue
                    
                # Extract file
                zip_ref.extract(file_name, work_dir)
                extracted_files.append(file_name)
        
        # Remove temporary ZIP file
        temp_zip.unlink()
        
        # Reset reader to pick up new files
        reset_reader()
        
        return [TextContent(
            type="text",
            text=f"Successfully uploaded and extracted archive: {len(extracted_files)} files extracted ({len(content)} bytes total)\n\nExtracted files:\n" + "\n".join(extracted_files[:20]) + ("\n... and more" if len(extracted_files) > 20 else "")
        )]
        
    except zipfile.BadZipFile:
        raise ValueError("Invalid ZIP file format")
    except Exception as e:
        raise ValueError(f"Failed to extract archive: {e}")


async def list_uploaded_files() -> List[TextContent]:
    """List all uploaded files."""
    work_dir = get_working_dir()
    
    if not work_dir.exists():
        return [TextContent(type="text", text="No files uploaded yet")]
    
    files = []
    for root, dirs, filenames in os.walk(work_dir):
        for filename in filenames:
            file_path = Path(root) / filename
            rel_path = file_path.relative_to(work_dir)
            size = file_path.stat().st_size
            files.append(f"{rel_path} ({size} bytes)")
    
    if not files:
        return [TextContent(type="text", text="No files uploaded yet")]
    
    return [TextContent(
        type="text",
        text=f"Uploaded files ({len(files)} total):\n" + "\n".join(files)
    )]


async def clear_uploaded_files() -> List[TextContent]:
    """Clear all uploaded files."""
    global working_dir, cpap_reader
    
    if working_dir and working_dir.exists():
        shutil.rmtree(working_dir)
    
    working_dir = None
    cpap_reader = None
    
    return [TextContent(type="text", text="Successfully cleared all uploaded files")]


async def get_devices() -> List[TextContent]:
    """Get device information."""
    reader = initialize_reader()
    devices = reader.get_devices()
    
    result = {
        "devices": [d.model_dump() for d in devices],
        "count": len(devices),
    }
    
    return [TextContent(
        type="text",
        text=json.dumps(result, indent=2, default=serialize_datetime)
    )]


async def get_sessions(arguments: Dict[str, Any]) -> List[TextContent]:
    """Get therapy sessions with optional filtering."""
    reader = initialize_reader()
    
    # Parse arguments
    device_id = arguments.get("device_id")
    start_date_str = arguments.get("start_date")
    end_date_str = arguments.get("end_date")
    min_duration_hours = arguments.get("min_duration_hours", 0.0)
    
    # Parse dates
    start_date = None
    end_date = None
    if start_date_str:
        start_date = datetime.fromisoformat(start_date_str).date()
    if end_date_str:
        end_date = datetime.fromisoformat(end_date_str).date()
    
    # Get sessions
    sessions = reader.get_sessions(
        device_id=device_id,
        start_date=start_date,
        end_date=end_date,
        min_duration_hours=min_duration_hours,
    )
    
    result = {
        "sessions": [s.to_dict() for s in sessions],
        "count": len(sessions),
        "filters_applied": {
            "device_id": device_id,
            "start_date": start_date_str,
            "end_date": end_date_str,
            "min_duration_hours": min_duration_hours,
        },
    }
    
    return [TextContent(
        type="text",
        text=json.dumps(result, indent=2, default=serialize_datetime)
    )]


async def get_session_details(arguments: Dict[str, Any]) -> List[TextContent]:
    """Get detailed information about a specific session."""
    session_id = arguments.get("session_id")
    if not session_id:
        raise ValueError("session_id is required")
    
    reader = initialize_reader()
    sessions = reader.get_sessions()
    
    # Find the session
    session = next((s for s in sessions if s.session_id == session_id), None)
    if not session:
        raise ValueError(f"Session not found: {session_id}")
    
    result = session.to_dict()
    
    return [TextContent(
        type="text",
        text=json.dumps(result, indent=2, default=serialize_datetime)
    )]


async def get_session_events(arguments: Dict[str, Any]) -> List[TextContent]:
    """Get events for a specific session."""
    session_id = arguments.get("session_id")
    event_type_str = arguments.get("event_type")
    
    if not session_id:
        raise ValueError("session_id is required")
    
    reader = initialize_reader()
    sessions = reader.get_sessions()
    
    # Find the session
    session = next((s for s in sessions if s.session_id == session_id), None)
    if not session:
        raise ValueError(f"Session not found: {session_id}")
    
    # Parse event type
    event_type = None
    if event_type_str:
        try:
            event_type = EventType(event_type_str)
        except ValueError:
            raise ValueError(f"Invalid event type: {event_type_str}")
    
    # Get events
    events = session.get_events(event_type=event_type)
    
    result = {
        "session_id": session_id,
        "event_type_filter": event_type_str,
        "events": [
            {
                "type": e.type.value,
                "timestamp": e.timestamp.isoformat(),
                "duration": e.duration,
                "data": e.data,
            }
            for e in events
        ],
        "count": len(events),
    }
    
    return [TextContent(
        type="text",
        text=json.dumps(result, indent=2, default=serialize_datetime)
    )]


async def get_session_pressure_data(arguments: Dict[str, Any]) -> List[TextContent]:
    """Get pressure waveform data for a session."""
    session_id = arguments.get("session_id")
    sample_limit = arguments.get("sample_limit", 1000)
    
    if not session_id:
        raise ValueError("session_id is required")
    
    reader = initialize_reader()
    sessions = reader.get_sessions()
    
    # Find the session
    session = next((s for s in sessions if s.session_id == session_id), None)
    if not session:
        raise ValueError(f"Session not found: {session_id}")
    
    # Get pressure data
    df = session.get_pressure_data()
    
    if df is None or df.empty:
        return [TextContent(type="text", text="No pressure data available for this session")]
    
    # Limit samples
    if len(df) > sample_limit:
        # Sample evenly across the session
        step = len(df) // sample_limit
        df = df.iloc[::step][:sample_limit]
    
    result = {
        "session_id": session_id,
        "total_samples": len(df),
        "sample_limit_applied": sample_limit,
        "columns": list(df.columns),
        "data": df.to_dict(orient="records"),
    }
    
    return [TextContent(
        type="text",
        text=json.dumps(result, indent=2, default=serialize_datetime)
    )]


async def get_session_flow_data(arguments: Dict[str, Any]) -> List[TextContent]:
    """Get flow waveform data for a session."""
    session_id = arguments.get("session_id")
    sample_limit = arguments.get("sample_limit", 1000)
    
    if not session_id:
        raise ValueError("session_id is required")
    
    reader = initialize_reader()
    sessions = reader.get_sessions()
    
    # Find the session
    session = next((s for s in sessions if s.session_id == session_id), None)
    if not session:
        raise ValueError(f"Session not found: {session_id}")
    
    # Get flow data
    df = session.get_flow_data()
    
    if df is None or df.empty:
        return [TextContent(type="text", text="No flow data available for this session")]
    
    # Limit samples
    if len(df) > sample_limit:
        step = len(df) // sample_limit
        df = df.iloc[::step][:sample_limit]
    
    result = {
        "session_id": session_id,
        "total_samples": len(df),
        "sample_limit_applied": sample_limit,
        "columns": list(df.columns),
        "data": df.to_dict(orient="records"),
    }
    
    return [TextContent(
        type="text",
        text=json.dumps(result, indent=2, default=serialize_datetime)
    )]


async def get_session_spo2_data(arguments: Dict[str, Any]) -> List[TextContent]:
    """Get SpO2 waveform data for a session."""
    session_id = arguments.get("session_id")
    sample_limit = arguments.get("sample_limit", 1000)
    
    if not session_id:
        raise ValueError("session_id is required")
    
    reader = initialize_reader()
    sessions = reader.get_sessions()
    
    # Find the session
    session = next((s for s in sessions if s.session_id == session_id), None)
    if not session:
        raise ValueError(f"Session not found: {session_id}")
    
    # Get SpO2 data
    df = session.get_spo2_data()
    
    if df is None or df.empty:
        return [TextContent(type="text", text="No SpO2 data available for this session")]
    
    # Limit samples
    if len(df) > sample_limit:
        step = len(df) // sample_limit
        df = df.iloc[::step][:sample_limit]
    
    result = {
        "session_id": session_id,
        "total_samples": len(df),
        "sample_limit_applied": sample_limit,
        "columns": list(df.columns),
        "data": df.to_dict(orient="records"),
    }
    
    return [TextContent(
        type="text",
        text=json.dumps(result, indent=2, default=serialize_datetime)
    )]


async def get_summary_statistics(arguments: Dict[str, Any]) -> List[TextContent]:
    """Get aggregate statistics across sessions."""
    device_id = arguments.get("device_id")
    days = arguments.get("days", 30)
    
    reader = initialize_reader()
    stats = reader.get_summary_statistics(device_id=device_id, days=days)
    
    return [TextContent(
        type="text",
        text=json.dumps(stats, indent=2, default=serialize_datetime)
    )]


async def get_device_settings(arguments: Dict[str, Any]) -> List[TextContent]:
    """Get device settings from a session."""
    session_id = arguments.get("session_id")
    
    reader = initialize_reader()
    sessions = reader.get_sessions()
    
    if not sessions:
        return [TextContent(type="text", text="No sessions found")]
    
    # Use specified session or most recent
    if session_id:
        session = next((s for s in sessions if s.session_id == session_id), None)
        if not session:
            raise ValueError(f"Session not found: {session_id}")
    else:
        # Get most recent session
        session = max(sessions, key=lambda s: s.start_time)
    
    result = {
        "session_id": session.session_id,
        "settings": session.settings.model_dump(),
    }
    
    return [TextContent(
        type="text",
        text=json.dumps(result, indent=2, default=serialize_datetime)
    )]


async def analyze_therapy_effectiveness(arguments: Dict[str, Any]) -> List[TextContent]:
    """Analyze therapy effectiveness and provide insights."""
    days = arguments.get("days", 30)
    
    reader = initialize_reader()
    stats = reader.get_summary_statistics(days=days)
    
    if not stats or not stats.get("sessions"):
        return [TextContent(type="text", text="No session data available for analysis")]
    
    sessions = stats["sessions"]
    
    # Calculate trends and insights
    analysis = {
        "period_days": days,
        "total_sessions": stats["total_sessions"],
        "compliance": {
            "total_hours": stats["total_hours"],
            "average_hours_per_night": stats["average_hours_per_session"],
            "nights_with_4plus_hours": len([s for s in sessions if s["summary"]["duration_hours"] >= 4]),
            "compliance_percentage": len([s for s in sessions if s["summary"]["duration_hours"] >= 4]) / stats["total_sessions"] * 100 if stats["total_sessions"] > 0 else 0,
        },
        "therapy_effectiveness": {
            "average_ahi": stats.get("average_ahi"),
            "ahi_control": "excellent" if stats.get("average_ahi", 100) < 5 else "good" if stats.get("average_ahi", 100) < 15 else "needs_improvement",
            "sessions_with_high_ahi": len([s for s in sessions if s["summary"].get("ahi") and s["summary"]["ahi"] > 10]),
        },
        "leak_performance": {
            "average_leak_95th": stats.get("average_leak_95th"),
            "leak_status": "good" if stats.get("average_leak_95th", 100) < 24 else "high_leak_detected",
            "sessions_with_high_leak": len([s for s in sessions if s["summary"].get("leak_95th") and s["summary"]["leak_95th"] > 24]),
        },
        "recommendations": [],
    }
    
    # Generate recommendations
    if analysis["compliance"]["compliance_percentage"] < 70:
        analysis["recommendations"].append({
            "category": "compliance",
            "priority": "high",
            "message": "Compliance is below 70%. Consider addressing comfort issues or mask fit.",
        })
    
    if analysis["therapy_effectiveness"]["ahi_control"] == "needs_improvement":
        analysis["recommendations"].append({
            "category": "therapy_effectiveness",
            "priority": "high",
            "message": f"Average AHI of {stats.get('average_ahi', 0):.1f} indicates suboptimal therapy. Consider pressure adjustments or consulting your provider.",
        })
    
    if analysis["leak_performance"]["leak_status"] == "high_leak_detected":
        analysis["recommendations"].append({
            "category": "leak",
            "priority": "medium",
            "message": "High leak rates detected. Check mask fit and consider trying a different mask size or style.",
        })
    
    if not analysis["recommendations"]:
        analysis["recommendations"].append({
            "category": "general",
            "priority": "info",
            "message": "Therapy appears to be working well. Continue current settings and maintain good compliance.",
        })
    
    return [TextContent(
        type="text",
        text=json.dumps(analysis, indent=2, default=serialize_datetime)
    )]


async def get_validation_errors() -> List[TextContent]:
    """Get validation errors encountered during parsing."""
    reader = initialize_reader()
    errors = reader.get_validation_errors()
    
    result = {
        "validation_errors": [e.model_dump() for e in errors],
        "count": len(errors),
        "has_errors": any(e.severity == "error" for e in errors),
        "has_warnings": any(e.severity == "warning" for e in errors),
    }
    
    return [TextContent(
        type="text",
        text=json.dumps(result, indent=2, default=serialize_datetime)
    )]


async def export_all_data() -> List[TextContent]:
    """Export complete data export from CPAPReader."""
    reader = initialize_reader()
    data = reader.export_to_dict()
    
    return [TextContent(
        type="text",
        text=json.dumps(data, indent=2, default=serialize_datetime)
    )]


async def propose_pressure_adjustment(arguments: Dict[str, Any]) -> List[TextContent]:
    """Generate a pressure adjustment proposal."""
    target_pressure = arguments.get("target_pressure")
    reason = arguments.get("reason")
    session_id = arguments.get("session_id")
    
    if not target_pressure or not reason:
        raise ValueError("target_pressure and reason are required")
    
    reader = initialize_reader()
    sessions = reader.get_sessions()
    
    if not sessions:
        return [TextContent(type="text", text="No sessions found to get current settings")]
    
    # Use specified session or most recent
    if session_id:
        session = next((s for s in sessions if s.session_id == session_id), None)
        if not session:
            raise ValueError(f"Session not found: {session_id}")
    else:
        session = max(sessions, key=lambda s: s.start_time)
    
    # Get device info
    devices = reader.get_devices()
    device_serial = devices[0].serial_number if devices else "UNKNOWN"
    
    # Get current AHI if available
    current_ahi = session.summary.ahi
    
    # Create proposal
    proposal = create_pressure_adjustment_proposal(
        device_serial=device_serial,
        current_settings=session.settings,
        target_pressure=target_pressure,
        reason=reason,
        ahi=current_ahi,
    )
    
    return [TextContent(
        type="text",
        text=json.dumps(proposal.to_dict(), indent=2, default=serialize_datetime)
    )]


async def propose_comfort_improvements(arguments: Dict[str, Any]) -> List[TextContent]:
    """Generate a comfort improvement proposal."""
    enable_epr = arguments.get("enable_epr", True)
    epr_level = arguments.get("epr_level", 2)
    enable_ramp = arguments.get("enable_ramp", True)
    ramp_time = arguments.get("ramp_time", 20)
    session_id = arguments.get("session_id")
    
    reader = initialize_reader()
    sessions = reader.get_sessions()
    
    if not sessions:
        return [TextContent(type="text", text="No sessions found to get current settings")]
    
    # Use specified session or most recent
    if session_id:
        session = next((s for s in sessions if s.session_id == session_id), None)
        if not session:
            raise ValueError(f"Session not found: {session_id}")
    else:
        session = max(sessions, key=lambda s: s.start_time)
    
    # Get device info
    devices = reader.get_devices()
    device_serial = devices[0].serial_number if devices else "UNKNOWN"
    
    # Create proposal
    proposal = create_comfort_improvement_proposal(
        device_serial=device_serial,
        current_settings=session.settings,
        enable_epr=enable_epr,
        epr_level=epr_level,
        enable_ramp=enable_ramp,
        ramp_time=ramp_time,
    )
    
    return [TextContent(
        type="text",
        text=json.dumps(proposal.to_dict(), indent=2, default=serialize_datetime)
    )]


async def main():
    """Main entry point for the MCP server."""
    async with stdio_server() as (read_stream, write_stream):
        await app.run(
            read_stream,
            write_stream,
            app.create_initialization_options()
        )


def run():
    """Synchronous entry point."""
    asyncio.run(main())


if __name__ == "__main__":
    run()
