"""
Additional unit tests for edge cases and coverage.
"""

import pytest
import pandas as pd
from unittest.mock import Mock, patch
from datetime import datetime


pytestmark = pytest.mark.unit


class TestInitializeReader:
    """Test reader initialization."""

    def test_initialize_reader_creates_reader(self):
        """Test that initialize_reader creates a CPAPReader."""
        from cpap_mcp.server import get_working_dir, initialize_reader
        import cpap_mcp.server as server_module
        
        # Reset state
        server_module.cpap_reader = None
        
        # Create working dir
        work_dir = get_working_dir()
        work_dir.mkdir(parents=True, exist_ok=True)
        
        # This will fail without actual CPAP data, but tests the path
        with patch('cpap_mcp.server.CPAPReader') as mock_reader_class:
            mock_reader = Mock()
            mock_reader_class.return_value = mock_reader
            
            reader = initialize_reader()
            assert reader is not None
            mock_reader_class.assert_called_once()

    def test_initialize_reader_reuses_existing(self):
        """Test that initialize_reader reuses existing reader."""
        import cpap_mcp.server as server_module
        
        mock_reader = Mock()
        server_module.cpap_reader = mock_reader
        
        from cpap_mcp.server import initialize_reader
        reader = initialize_reader()
        assert reader is mock_reader

    def test_initialize_reader_fails_without_workdir(self):
        """Test that initialize_reader fails without working directory."""
        import cpap_mcp.server as server_module
        from cpap_mcp.server import initialize_reader
        
        # Reset state
        server_module.cpap_reader = None
        server_module.working_dir = None
        
        # Should create working_dir but fail if it doesn't exist after creation
        with patch('cpap_mcp.server.get_working_dir') as mock_get_dir:
            mock_dir = Mock()
            mock_dir.exists.return_value = False
            mock_get_dir.return_value = mock_dir
            
            with pytest.raises(ValueError, match="Working directory not initialized"):
                initialize_reader()


@pytest.mark.asyncio
class TestWaveformDataWithDataFrames:
    """Test waveform data operations with actual dataframes."""

    @patch('cpap_mcp.server.initialize_reader')
    async def test_get_pressure_data_with_sampling(self, mock_init_reader):
        """Test pressure data with sample limiting."""
        from cpap_mcp.server import get_session_pressure_data
        
        # Create a large dataframe
        df = pd.DataFrame({
            'timestamp': pd.date_range('2024-01-01', periods=10000, freq='1S'),
            'pressure': [10.0] * 10000
        })
        
        mock_session = Mock()
        mock_session.session_id = "test123"
        mock_session.get_pressure_data.return_value = df
        
        mock_reader = Mock()
        mock_reader.get_sessions.return_value = [mock_session]
        mock_init_reader.return_value = mock_reader
        
        result = await get_session_pressure_data({
            "session_id": "test123",
            "sample_limit": 100
        })
        
        import json
        data = json.loads(result[0].text)
        assert data["sample_limit_applied"] == 100
        assert len(data["data"]) <= 100

    @patch('cpap_mcp.server.initialize_reader')
    async def test_get_flow_data_with_data(self, mock_init_reader):
        """Test flow data with actual dataframe."""
        from cpap_mcp.server import get_session_flow_data
        
        df = pd.DataFrame({
            'timestamp': pd.date_range('2024-01-01', periods=100, freq='1S'),
            'flow': [0.5] * 100
        })
        
        mock_session = Mock()
        mock_session.session_id = "test123"
        mock_session.get_flow_data.return_value = df
        
        mock_reader = Mock()
        mock_reader.get_sessions.return_value = [mock_session]
        mock_init_reader.return_value = mock_reader
        
        result = await get_session_flow_data({"session_id": "test123"})
        
        import json
        data = json.loads(result[0].text)
        assert "columns" in data
        assert "data" in data

    @patch('cpap_mcp.server.initialize_reader')
    async def test_get_spo2_data_empty_dataframe(self, mock_init_reader):
        """Test SpO2 data with empty dataframe."""
        from cpap_mcp.server import get_session_spo2_data
        
        df = pd.DataFrame()
        
        mock_session = Mock()
        mock_session.session_id = "test123"
        mock_session.get_spo2_data.return_value = df
        
        mock_reader = Mock()
        mock_reader.get_sessions.return_value = [mock_session]
        mock_init_reader.return_value = mock_reader
        
        result = await get_session_spo2_data({"session_id": "test123"})
        assert "No SpO2 data available" in result[0].text


@pytest.mark.asyncio
class TestDeviceSettingsEdgeCases:
    """Test device settings edge cases."""

    @patch('cpap_mcp.server.initialize_reader')
    async def test_get_device_settings_with_session_id(self, mock_init_reader):
        """Test getting device settings with specific session."""
        from cpap_mcp.server import get_device_settings
        
        mock_settings = Mock()
        mock_settings.model_dump.return_value = {"mode": "APAP"}
        
        mock_session1 = Mock()
        mock_session1.session_id = "session1"
        mock_session1.start_time = datetime(2024, 1, 1)
        mock_session1.settings = mock_settings
        
        mock_session2 = Mock()
        mock_session2.session_id = "session2"
        mock_session2.start_time = datetime(2024, 1, 2)
        mock_session2.settings = mock_settings
        
        mock_reader = Mock()
        mock_reader.get_sessions.return_value = [mock_session1, mock_session2]
        mock_init_reader.return_value = mock_reader
        
        result = await get_device_settings({"session_id": "session1"})
        
        import json
        data = json.loads(result[0].text)
        assert data["session_id"] == "session1"

    @patch('cpap_mcp.server.initialize_reader')
    async def test_get_device_settings_most_recent(self, mock_init_reader):
        """Test getting device settings from most recent session."""
        from cpap_mcp.server import get_device_settings
        
        mock_settings = Mock()
        mock_settings.model_dump.return_value = {"mode": "APAP"}
        
        mock_session1 = Mock()
        mock_session1.session_id = "session1"
        mock_session1.start_time = datetime(2024, 1, 1)
        mock_session1.settings = mock_settings
        
        mock_session2 = Mock()
        mock_session2.session_id = "session2"
        mock_session2.start_time = datetime(2024, 1, 2)
        mock_session2.settings = mock_settings
        
        mock_reader = Mock()
        mock_reader.get_sessions.return_value = [mock_session1, mock_session2]
        mock_init_reader.return_value = mock_reader
        
        result = await get_device_settings({})
        
        import json
        data = json.loads(result[0].text)
        assert data["session_id"] == "session2"  # Most recent

    @patch('cpap_mcp.server.initialize_reader')
    async def test_get_device_settings_session_not_found(self, mock_init_reader):
        """Test getting device settings with invalid session ID."""
        from cpap_mcp.server import get_device_settings
        
        mock_reader = Mock()
        mock_reader.get_sessions.return_value = []
        mock_init_reader.return_value = mock_reader
        
        result = await get_device_settings({"session_id": "invalid"})
        assert "Error" in result[0].text or "No sessions" in result[0].text


@pytest.mark.asyncio
class TestProposalsEdgeCases:
    """Test proposal edge cases."""

    @patch('cpap_mcp.server.initialize_reader')
    async def test_propose_pressure_adjustment_no_sessions(self, mock_init_reader):
        """Test pressure adjustment when no sessions exist."""
        from cpap_mcp.server import propose_pressure_adjustment
        
        mock_reader = Mock()
        mock_reader.get_sessions.return_value = []
        mock_init_reader.return_value = mock_reader
        
        result = await propose_pressure_adjustment({
            "target_pressure": 12.0,
            "reason": "Test"
        })
        assert "No sessions found" in result[0].text

    @patch('cpap_mcp.server.initialize_reader')
    async def test_propose_comfort_improvements_no_sessions(self, mock_init_reader):
        """Test comfort improvements when no sessions exist."""
        from cpap_mcp.server import propose_comfort_improvements
        
        mock_reader = Mock()
        mock_reader.get_sessions.return_value = []
        mock_init_reader.return_value = mock_reader
        
        result = await propose_comfort_improvements({})
        assert "No sessions found" in result[0].text

    @patch('cpap_mcp.server.initialize_reader')
    async def test_propose_pressure_adjustment_with_session_id(self, mock_init_reader):
        """Test pressure adjustment with specific session."""
        from cpap_mcp.server import propose_pressure_adjustment
        
        mock_device = Mock()
        mock_device.serial_number = "12345678"
        
        mock_summary = Mock()
        mock_summary.ahi = 8.5
        
        mock_session = Mock()
        mock_session.session_id = "session1"
        mock_session.start_time = datetime(2024, 1, 1)
        mock_session.settings = Mock()
        mock_session.summary = mock_summary
        
        mock_reader = Mock()
        mock_reader.get_sessions.return_value = [mock_session]
        mock_reader.get_devices.return_value = [mock_device]
        mock_init_reader.return_value = mock_reader
        
        with patch('cpap_mcp.server.create_pressure_adjustment_proposal') as mock_create:
            mock_proposal = Mock()
            mock_proposal.to_dict.return_value = {"test": "proposal"}
            mock_create.return_value = mock_proposal
            
            result = await propose_pressure_adjustment({
                "target_pressure": 12.0,
                "reason": "High AHI",
                "session_id": "session1"
            })
            
            mock_create.assert_called_once()


@pytest.mark.asyncio
class TestAnalysisRecommendations:
    """Test therapy analysis recommendations."""

    @patch('cpap_mcp.server.initialize_reader')
    async def test_analyze_with_poor_compliance(self, mock_init_reader):
        """Test analysis with poor compliance generates recommendations."""
        from cpap_mcp.server import analyze_therapy_effectiveness
        
        mock_reader = Mock()
        mock_reader.get_summary_statistics.return_value = {
            "sessions": [
                {"summary": {"duration_hours": 3.0, "ahi": 3.0, "leak_95th": 10}},
                {"summary": {"duration_hours": 2.5, "ahi": 4.0, "leak_95th": 12}},
            ],
            "total_sessions": 2,
            "total_hours": 5.5,
            "average_hours_per_session": 2.75,
            "average_ahi": 3.5,
            "average_leak_95th": 11,
        }
        mock_init_reader.return_value = mock_reader
        
        result = await analyze_therapy_effectiveness({"days": 30})
        
        import json
        data = json.loads(result[0].text)
        assert any("compliance" in rec["category"] for rec in data["recommendations"])

    @patch('cpap_mcp.server.initialize_reader')
    async def test_analyze_with_high_ahi(self, mock_init_reader):
        """Test analysis with high AHI generates recommendations."""
        from cpap_mcp.server import analyze_therapy_effectiveness
        
        mock_reader = Mock()
        mock_reader.get_summary_statistics.return_value = {
            "sessions": [
                {"summary": {"duration_hours": 7.0, "ahi": 18.0, "leak_95th": 10}},
                {"summary": {"duration_hours": 7.5, "ahi": 20.0, "leak_95th": 12}},
            ],
            "total_sessions": 2,
            "total_hours": 14.5,
            "average_hours_per_session": 7.25,
            "average_ahi": 19.0,
            "average_leak_95th": 11,
        }
        mock_init_reader.return_value = mock_reader
        
        result = await analyze_therapy_effectiveness({"days": 30})
        
        import json
        data = json.loads(result[0].text)
        assert any("therapy_effectiveness" in rec["category"] for rec in data["recommendations"])

    @patch('cpap_mcp.server.initialize_reader')
    async def test_analyze_with_high_leak(self, mock_init_reader):
        """Test analysis with high leak generates recommendations."""
        from cpap_mcp.server import analyze_therapy_effectiveness
        
        mock_reader = Mock()
        mock_reader.get_summary_statistics.return_value = {
            "sessions": [
                {"summary": {"duration_hours": 7.0, "ahi": 3.0, "leak_95th": 30}},
                {"summary": {"duration_hours": 7.5, "ahi": 4.0, "leak_95th": 28}},
            ],
            "total_sessions": 2,
            "total_hours": 14.5,
            "average_hours_per_session": 7.25,
            "average_ahi": 3.5,
            "average_leak_95th": 29,
        }
        mock_init_reader.return_value = mock_reader
        
        result = await analyze_therapy_effectiveness({"days": 30})
        
        import json
        data = json.loads(result[0].text)
        assert any("leak" in rec["category"] for rec in data["recommendations"])

    @patch('cpap_mcp.server.initialize_reader')
    async def test_analyze_with_good_therapy(self, mock_init_reader):
        """Test analysis with good therapy generates positive message."""
        from cpap_mcp.server import analyze_therapy_effectiveness
        
        mock_reader = Mock()
        mock_reader.get_summary_statistics.return_value = {
            "sessions": [
                {"summary": {"duration_hours": 7.5, "ahi": 2.0, "leak_95th": 10}},
                {"summary": {"duration_hours": 8.0, "ahi": 3.0, "leak_95th": 12}},
            ],
            "total_sessions": 2,
            "total_hours": 15.5,
            "average_hours_per_session": 7.75,
            "average_ahi": 2.5,
            "average_leak_95th": 11,
        }
        mock_init_reader.return_value = mock_reader
        
        result = await analyze_therapy_effectiveness({"days": 30})
        
        import json
        data = json.loads(result[0].text)
        assert len(data["recommendations"]) > 0
        assert data["therapy_effectiveness"]["ahi_control"] == "excellent"
