# allow: no-sut-import — black-box HTTP test; drives real routes through the Flask test client
"""Tests for save_raw_config and get_upload_limits in research_routes.py."""

from unittest.mock import patch

RESEARCH_PREFIX = ""


class TestSaveRawConfig:
    """Tests for /api/save_raw_config endpoint."""

    def test_requires_authentication(self, client):
        response = client.post(
            f"{RESEARCH_PREFIX}/api/save_raw_config",
            json={"raw_config": "[search]\ntool = 'google'"},
        )
        assert response.status_code in [401, 302]

    def test_missing_raw_config(self, authenticated_client):
        response = authenticated_client.post(
            f"{RESEARCH_PREFIX}/api/save_raw_config",
            json={},
        )
        assert response.status_code == 400
        data = response.get_json()
        assert data["success"] is False

    def test_empty_raw_config(self, authenticated_client):
        response = authenticated_client.post(
            f"{RESEARCH_PREFIX}/api/save_raw_config",
            json={"raw_config": ""},
        )
        assert response.status_code == 400

    def test_invalid_toml_syntax(self, authenticated_client):
        response = authenticated_client.post(
            f"{RESEARCH_PREFIX}/api/save_raw_config",
            json={"raw_config": "this is {{not valid toml"},
        )
        assert response.status_code == 400
        data = response.get_json()
        assert data["success"] is False
        assert "TOML" in data["error"]

    def test_blocked_key_module_path(self, authenticated_client):
        """Config with module_path key should be rejected."""
        toml_config = '[custom]\nmodule_path = "evil.module"'
        response = authenticated_client.post(
            f"{RESEARCH_PREFIX}/api/save_raw_config",
            json={"raw_config": toml_config},
        )
        assert response.status_code == 403
        data = response.get_json()
        assert data["success"] is False
        assert "blocked_keys" in data

    def test_blocked_key_class_name(self, authenticated_client):
        """Config with class_name key should be rejected."""
        toml_config = '[providers]\nclass_name = "EvilClass"'
        response = authenticated_client.post(
            f"{RESEARCH_PREFIX}/api/save_raw_config",
            json={"raw_config": toml_config},
        )
        assert response.status_code == 403

    def test_blocked_key_nested(self, authenticated_client):
        """Blocked keys in nested dicts should also be caught."""
        toml_config = '[a.b]\nmodule = "evil"'
        response = authenticated_client.post(
            f"{RESEARCH_PREFIX}/api/save_raw_config",
            json={"raw_config": toml_config},
        )
        assert response.status_code == 403

    @patch(
        "local_deep_research.security.file_write_verifier.write_file_verified"
    )
    @patch(
        "local_deep_research.web.routes.research_routes.get_config_directory"
    )
    def test_valid_config_saved(
        self, mock_config_dir, mock_write, authenticated_client, tmp_path
    ):
        mock_config_dir.return_value = tmp_path

        toml_config = '[search]\ntool = "google"\niterations = 5'
        response = authenticated_client.post(
            f"{RESEARCH_PREFIX}/api/save_raw_config",
            json={"raw_config": toml_config},
        )
        assert response.status_code == 200
        data = response.get_json()
        assert data["success"] is True
        mock_write.assert_called_once()

    @patch(
        "local_deep_research.security.file_write_verifier.write_file_verified"
    )
    @patch(
        "local_deep_research.web.routes.research_routes.get_config_directory"
    )
    def test_write_error_returns_500(
        self, mock_config_dir, mock_write, authenticated_client, tmp_path
    ):
        mock_config_dir.return_value = tmp_path
        mock_write.side_effect = RuntimeError("write failed")

        toml_config = '[search]\ntool = "google"'
        response = authenticated_client.post(
            f"{RESEARCH_PREFIX}/api/save_raw_config",
            json={"raw_config": toml_config},
        )
        assert response.status_code == 500

    def test_no_json_body(self, authenticated_client):
        """Missing JSON body should be rejected."""
        response = authenticated_client.post(
            f"{RESEARCH_PREFIX}/api/save_raw_config",
            content_type="application/json",
        )
        # require_json_body decorator handles this
        assert response.status_code == 400

    def test_does_not_expose_internal_errors(self, authenticated_client):
        """Invalid TOML should not expose exception details."""
        response = authenticated_client.post(
            f"{RESEARCH_PREFIX}/api/save_raw_config",
            json={"raw_config": "invalid = [unclosed"},
        )
        data = response.get_json()
        # Should show generic message, not Python traceback
        assert "TOML" in data["error"]
        assert "Traceback" not in data.get("error", "")


class TestGetUploadLimits:
    """Tests for /api/upload/limits endpoint."""

    def test_requires_authentication(self, client):
        response = client.get(f"{RESEARCH_PREFIX}/api/config/limits")
        assert response.status_code == 401

    def test_returns_upload_limits(self, authenticated_client):
        response = authenticated_client.get(
            f"{RESEARCH_PREFIX}/api/config/limits"
        )
        assert response.status_code == 200
        data = response.get_json()
        assert "max_file_size" in data
        assert "max_files" in data
        assert "allowed_mime_types" in data
        assert isinstance(data["max_file_size"], int)
        assert isinstance(data["max_files"], int)
        assert isinstance(data["allowed_mime_types"], list)

    def test_mime_types_include_pdf(self, authenticated_client):
        response = authenticated_client.get(
            f"{RESEARCH_PREFIX}/api/config/limits"
        )
        data = response.get_json()
        assert "application/pdf" in data["allowed_mime_types"]
