# -*- coding: utf-8 -*-
"""Location: ./tests/unit/mcpgateway/routers/test_metrics_maintenance.py
Copyright 2026
SPDX-License-Identifier: Apache-2.0
Authors: Mihai Criveti

Tests for metrics maintenance router.
"""

# Standard
from datetime import datetime, timezone
from unittest.mock import AsyncMock, MagicMock, patch

# Third-Party
from fastapi.testclient import TestClient
import pytest

# First-Party
from mcpgateway.utils.verify_credentials import require_admin_auth


def test_metrics_config_includes_delete_raw_after_rollup_hours(app):
    """Test config endpoint includes delete_raw_after_rollup_hours."""
    app.dependency_overrides[require_admin_auth] = lambda: "test_admin"
    client = TestClient(app)

    response = client.get("/api/metrics/config")

    assert response.status_code == 200
    payload = response.json()
    assert "rollup" in payload
    assert "delete_raw_after_rollup_hours" in payload["rollup"]

    app.dependency_overrides.pop(require_admin_auth, None)


def test_metrics_config_includes_all_settings(app):
    """Test config endpoint returns all expected settings."""
    app.dependency_overrides[require_admin_auth] = lambda: "test_admin"
    client = TestClient(app)

    response = client.get("/api/metrics/config")

    assert response.status_code == 200
    payload = response.json()
    assert "cleanup" in payload
    assert "rollup" in payload
    # Check cleanup keys
    assert "enabled" in payload["cleanup"]
    assert "retention_days" in payload["cleanup"]
    assert "interval_hours" in payload["cleanup"]
    assert "batch_size" in payload["cleanup"]
    # Check rollup keys
    assert "enabled" in payload["rollup"]
    assert "interval_hours" in payload["rollup"]
    assert "retention_days" in payload["rollup"]
    assert "late_data_hours" in payload["rollup"]
    assert "delete_raw_after_rollup" in payload["rollup"]

    app.dependency_overrides.pop(require_admin_auth, None)


def test_metrics_cleanup_disabled(app):
    """Test cleanup endpoint returns 400 when disabled."""
    app.dependency_overrides[require_admin_auth] = lambda: "test_admin"
    client = TestClient(app)

    with patch("mcpgateway.config.settings.csrf_enabled", False):
        with patch("mcpgateway.routers.metrics_maintenance.settings") as mock_settings:
            mock_settings.metrics_cleanup_enabled = False

            response = client.post("/api/metrics/cleanup", json={})

            assert response.status_code == 400
            assert "disabled" in response.json()["detail"].lower()

    app.dependency_overrides.pop(require_admin_auth, None)


def test_metrics_cleanup_all_tables(app):
    """Test cleanup endpoint cleans all tables when enabled."""
    app.dependency_overrides[require_admin_auth] = lambda: "test_admin"
    client = TestClient(app)

    with patch("mcpgateway.config.settings.csrf_enabled", False):
        with patch("mcpgateway.routers.metrics_maintenance.settings") as mock_settings:
            mock_settings.metrics_cleanup_enabled = True

            # Create mock result for cleanup_all
            mock_table_result = MagicMock()
            mock_table_result.table_name = "tool_metric"
            mock_table_result.deleted_count = 10
            mock_table_result.remaining_count = 100
            mock_table_result.cutoff_date = datetime.now(timezone.utc)
            mock_table_result.duration_seconds = 0.5
            mock_table_result.error = None

            mock_summary = MagicMock()
            mock_summary.total_deleted = 10
            mock_summary.tables = {"tool_metric": mock_table_result}
            mock_summary.duration_seconds = 0.5
            mock_summary.started_at = datetime.now(timezone.utc)
            mock_summary.completed_at = datetime.now(timezone.utc)

            with patch("mcpgateway.services.metrics_cleanup_service.get_metrics_cleanup_service") as mock_get_service:
                mock_service = MagicMock()
                mock_service.cleanup_all = AsyncMock(return_value=mock_summary)
                mock_get_service.return_value = mock_service

                response = client.post("/api/metrics/cleanup", json={})

                assert response.status_code == 200
                data = response.json()
                assert data["total_deleted"] == 10
                assert "tool_metric" in data["tables"]

    app.dependency_overrides.pop(require_admin_auth, None)


def test_metrics_cleanup_specific_table(app):
    """Test cleanup endpoint for specific table."""
    app.dependency_overrides[require_admin_auth] = lambda: "test_admin"
    client = TestClient(app)

    with patch("mcpgateway.config.settings.csrf_enabled", False):
        with patch("mcpgateway.routers.metrics_maintenance.settings") as mock_settings:
            mock_settings.metrics_cleanup_enabled = True

            mock_result = MagicMock()
            mock_result.table_name = "prompt_metric"
            mock_result.deleted_count = 5
            mock_result.remaining_count = 50
            mock_result.cutoff_date = datetime.now(timezone.utc)
            mock_result.duration_seconds = 0.3
            mock_result.error = None

            with patch("mcpgateway.services.metrics_cleanup_service.get_metrics_cleanup_service") as mock_get_service:
                mock_service = MagicMock()
                mock_service.cleanup_table = AsyncMock(return_value=mock_result)
                mock_get_service.return_value = mock_service

                response = client.post("/api/metrics/cleanup", json={"table_type": "prompt"})

                assert response.status_code == 200
                data = response.json()
                assert data["total_deleted"] == 5
                assert "prompt_metric" in data["tables"]

    app.dependency_overrides.pop(require_admin_auth, None)


def test_metrics_cleanup_invalid_table_type(app):
    """Test cleanup endpoint returns 400 for invalid table type."""
    app.dependency_overrides[require_admin_auth] = lambda: "test_admin"
    client = TestClient(app)

    with patch("mcpgateway.config.settings.csrf_enabled", False):
        with patch("mcpgateway.routers.metrics_maintenance.settings") as mock_settings:
            mock_settings.metrics_cleanup_enabled = True

            with patch("mcpgateway.services.metrics_cleanup_service.get_metrics_cleanup_service") as mock_get_service:
                mock_service = MagicMock()
                mock_service.cleanup_table = AsyncMock(side_effect=ValueError("Invalid table type"))
                mock_get_service.return_value = mock_service

                response = client.post("/api/metrics/cleanup", json={"table_type": "invalid"})

                assert response.status_code == 400
                assert "Invalid table type" in response.json()["detail"]

    app.dependency_overrides.pop(require_admin_auth, None)


def test_metrics_rollup_disabled(app):
    """Test rollup endpoint returns 400 when disabled."""
    app.dependency_overrides[require_admin_auth] = lambda: "test_admin"
    client = TestClient(app)

    with patch("mcpgateway.config.settings.csrf_enabled", False):
        with patch("mcpgateway.routers.metrics_maintenance.settings") as mock_settings:
            mock_settings.metrics_rollup_enabled = False

            response = client.post("/api/metrics/rollup", json={})

            assert response.status_code == 400
            assert "disabled" in response.json()["detail"].lower()

    app.dependency_overrides.pop(require_admin_auth, None)


def test_metrics_rollup_success(app):
    """Test rollup endpoint success."""
    app.dependency_overrides[require_admin_auth] = lambda: "test_admin"
    client = TestClient(app)

    with patch("mcpgateway.config.settings.csrf_enabled", False):
        with patch("mcpgateway.routers.metrics_maintenance.settings") as mock_settings:
            mock_settings.metrics_rollup_enabled = True

            mock_table_result = MagicMock()
            mock_table_result.table_name = "tool_metric"
            mock_table_result.hours_processed = 24
            mock_table_result.records_aggregated = 100
            mock_table_result.rollups_created = 24
            mock_table_result.rollups_updated = 0
            mock_table_result.raw_deleted = 100
            mock_table_result.duration_seconds = 1.0
            mock_table_result.error = None

            mock_summary = MagicMock()
            mock_summary.total_hours_processed = 24
            mock_summary.total_records_aggregated = 100
            mock_summary.total_rollups_created = 24
            mock_summary.total_rollups_updated = 0
            mock_summary.tables = {"tool_metric": mock_table_result}
            mock_summary.duration_seconds = 1.0
            mock_summary.started_at = datetime.now(timezone.utc)
            mock_summary.completed_at = datetime.now(timezone.utc)

            with patch("mcpgateway.services.metrics_rollup_service.get_metrics_rollup_service") as mock_get_service:
                mock_service = MagicMock()
                mock_service.rollup_all = AsyncMock(return_value=mock_summary)
                mock_get_service.return_value = mock_service

                response = client.post("/api/metrics/rollup", json={"hours_back": 24})

                assert response.status_code == 200
                data = response.json()
                assert data["total_hours_processed"] == 24
                assert data["total_records_aggregated"] == 100
                assert "tool_metric" in data["tables"]

    app.dependency_overrides.pop(require_admin_auth, None)


def test_metrics_stats_disabled(app):
    """Test stats endpoint when services are disabled."""
    app.dependency_overrides[require_admin_auth] = lambda: "test_admin"
    client = TestClient(app)

    with patch("mcpgateway.routers.metrics_maintenance.settings") as mock_settings:
        mock_settings.metrics_cleanup_enabled = False
        mock_settings.metrics_rollup_enabled = False

        response = client.get("/api/metrics/stats")

        assert response.status_code == 200
        data = response.json()
        assert data["cleanup"]["enabled"] is False
        assert data["rollup"]["enabled"] is False
        assert data["table_sizes"] == {}

    app.dependency_overrides.pop(require_admin_auth, None)


def test_metrics_stats_enabled(app):
    """Test stats endpoint when services are enabled."""
    app.dependency_overrides[require_admin_auth] = lambda: "test_admin"
    client = TestClient(app)

    with patch("mcpgateway.routers.metrics_maintenance.settings") as mock_settings:
        mock_settings.metrics_cleanup_enabled = True
        mock_settings.metrics_rollup_enabled = True

        with (
            patch("mcpgateway.services.metrics_cleanup_service.get_metrics_cleanup_service") as mock_cleanup,
            patch("mcpgateway.services.metrics_rollup_service.get_metrics_rollup_service") as mock_rollup,
        ):
            mock_cleanup_service = MagicMock()
            mock_cleanup_service.get_stats.return_value = {"enabled": True, "last_run": None}
            mock_cleanup_service.get_table_sizes = AsyncMock(return_value={"tool_metric": 100})
            mock_cleanup.return_value = mock_cleanup_service

            mock_rollup_service = MagicMock()
            mock_rollup_service.get_stats.return_value = {"enabled": True, "last_run": None}
            mock_rollup.return_value = mock_rollup_service

            response = client.get("/api/metrics/stats")

            assert response.status_code == 200
            data = response.json()
            assert data["cleanup"]["enabled"] is True
            assert data["rollup"]["enabled"] is True
            assert data["table_sizes"]["tool_metric"] == 100

    app.dependency_overrides.pop(require_admin_auth, None)
