"""Tests for list_models and load_model S3 tools."""

import os
from pathlib import Path

import pytest

from tests.conftest import S3_BUCKET, S3_PREFIX


class TestListModels:
    def test_no_s3_configured(self, mock_model, monkeypatch):
        monkeypatch.delenv("MERIDIAN_S3_BUCKET", raising=False)
        from mcp_server_meridian.server import list_models

        result = list_models()
        assert "error" in result
        assert "S3 is not configured" in result["error"]

    def test_lists_pkl_files_only(self, mock_model, mock_s3):
        from mcp_server_meridian.server import list_models

        result = list_models()
        assert "error" not in result
        assert result["count"] == 2
        names = [m["name"] for m in result["models"]]
        assert "client_20260301.pkl" in names
        assert "client_20260201.pkl" in names
        assert "readme.txt" not in names

    def test_returns_bucket_and_prefix(self, mock_model, mock_s3):
        from mcp_server_meridian.server import list_models

        result = list_models()
        assert result["bucket"] == S3_BUCKET
        assert result["prefix"] == S3_PREFIX

    def test_size_in_mb(self, mock_model, mock_s3):
        from mcp_server_meridian.server import list_models

        result = list_models()
        march = next(m for m in result["models"] if "0301" in m["name"])
        assert march["size_mb"] == pytest.approx(50.0, abs=0.1)

    def test_indicates_loaded_model(self, mock_model, mock_s3, monkeypatch):
        import mcp_server_meridian.server as srv

        monkeypatch.setattr(srv, "_loaded_model_name", "client_20260301.pkl")
        from mcp_server_meridian.server import list_models

        result = list_models()
        march = next(m for m in result["models"] if "0301" in m["name"])
        feb = next(m for m in result["models"] if "0201" in m["name"])
        assert march["is_loaded"] is True
        assert feb["is_loaded"] is False

    def test_empty_bucket(self, mock_model, mock_s3):
        # Override paginator to return empty
        mock_s3.get_paginator.return_value.paginate.return_value = [{"Contents": []}]
        from mcp_server_meridian.server import list_models

        result = list_models()
        assert result["count"] == 0
        assert result["models"] == []


class TestLoadModel:
    def test_load_from_s3_downloads_and_loads(self, mock_model, mock_s3, monkeypatch, tmp_path):
        monkeypatch.setenv("MERIDIAN_CACHE_DIR", str(tmp_path))

        import mcp_server_meridian.server as srv

        # Make download_file create the file, then patch _load_model to avoid real load
        def fake_download(bucket, key, path):
            Path(path).touch()

        mock_s3.download_file.side_effect = fake_download

        # Patch _load_model at the module level to track calls without real loading
        load_calls = []

        def tracking_load(path=None):
            load_calls.append(path)
            # Don't actually load, just set the name
            srv._loaded_model_name = os.path.basename(path) if path else None

        monkeypatch.setattr(srv, "_load_model", tracking_load)

        # Patch get_model_summary to return a stub
        monkeypatch.setattr(srv, "get_model_summary", lambda: {"model_name": "client_20260301"})

        from mcp_server_meridian.server import load_model

        result = load_model(name="client_20260301.pkl")
        assert "error" not in result
        mock_s3.download_file.assert_called_once()
        assert len(load_calls) == 1
        assert "client_20260301.pkl" in load_calls[0]

    def test_load_uses_cache(self, mock_model, mock_s3, monkeypatch, tmp_path):
        monkeypatch.setenv("MERIDIAN_CACHE_DIR", str(tmp_path))

        import mcp_server_meridian.server as srv

        # Pre-create cached file
        cached = tmp_path / "client_20260301.pkl"
        cached.touch()

        monkeypatch.setattr(srv, "_load_model", lambda path=None: None)
        monkeypatch.setattr(srv, "get_model_summary", lambda: {"model_name": "cached"})

        from mcp_server_meridian.server import load_model

        load_model(name="client_20260301.pkl")
        # Should NOT have called download since file exists
        mock_s3.download_file.assert_not_called()

    def test_load_local_path_no_s3(self, mock_model, monkeypatch, tmp_path):
        monkeypatch.delenv("MERIDIAN_S3_BUCKET", raising=False)

        import mcp_server_meridian.server as srv

        load_calls = []
        monkeypatch.setattr(srv, "_load_model", lambda path=None: load_calls.append(path))
        monkeypatch.setattr(srv, "get_model_summary", lambda: {"model_name": "local"})

        from mcp_server_meridian.server import load_model

        load_model(name="/some/local/model.pkl")
        assert load_calls == ["/some/local/model.pkl"]

    def test_s3_download_error(self, mock_model, mock_s3, monkeypatch, tmp_path):
        monkeypatch.setenv("MERIDIAN_CACHE_DIR", str(tmp_path))
        mock_s3.download_file.side_effect = Exception("Access Denied")

        from mcp_server_meridian.server import load_model

        result = load_model(name="nonexistent.pkl")
        assert "error" in result
        assert "Access Denied" in result["error"]


class TestResetModel:
    def test_reset_clears_state(self, mock_model):
        import mcp_server_meridian.server as srv

        assert srv._model is not None
        srv._reset_model()
        assert srv._model is None
        assert srv._trace is None
        assert srv._posterior is None
        assert srv._loaded_model_name is None
