"""
Tests for backup router endpoints.

This test suite validates REST API endpoints for backup management
including authentication, request validation, and response formatting.
"""

from unittest.mock import MagicMock, patch

import pytest
from fastapi.testclient import TestClient

from main import app
from tests.conftest import VALID_TEST_GRAPH_ID


class TestBackupEndpoints:
  """Test suite for backup REST API endpoints."""

  @pytest.fixture
  def client(self):
    """Create test client with rate limiting disabled."""
    from robosystems.middleware.rate_limits import (
      analytics_rate_limit_dependency,
      auth_rate_limit_dependency,
      auth_status_rate_limit_dependency,
      backup_operations_rate_limit_dependency,
      connection_management_rate_limit_dependency,
      general_api_rate_limit_dependency,
      graph_scoped_rate_limit_dependency,
      sensitive_auth_rate_limit_dependency,
      sso_rate_limit_dependency,
      subscription_aware_rate_limit_dependency,
      sync_operations_rate_limit_dependency,
      tasks_management_rate_limit_dependency,
      user_management_rate_limit_dependency,
    )

    # Save original overrides
    original_overrides = app.dependency_overrides.copy()

    # Disable rate limiting during tests
    app.dependency_overrides[auth_rate_limit_dependency] = lambda: None
    app.dependency_overrides[user_management_rate_limit_dependency] = lambda: None
    app.dependency_overrides[sync_operations_rate_limit_dependency] = lambda: None
    app.dependency_overrides[connection_management_rate_limit_dependency] = lambda: None
    app.dependency_overrides[analytics_rate_limit_dependency] = lambda: None
    app.dependency_overrides[backup_operations_rate_limit_dependency] = lambda: None
    app.dependency_overrides[sensitive_auth_rate_limit_dependency] = lambda: None
    app.dependency_overrides[tasks_management_rate_limit_dependency] = lambda: None
    app.dependency_overrides[general_api_rate_limit_dependency] = lambda: None
    app.dependency_overrides[subscription_aware_rate_limit_dependency] = lambda: None
    app.dependency_overrides[auth_status_rate_limit_dependency] = lambda: None
    app.dependency_overrides[sso_rate_limit_dependency] = lambda: None
    app.dependency_overrides[graph_scoped_rate_limit_dependency] = lambda: None

    client = TestClient(app)
    yield client

    # Restore original overrides
    app.dependency_overrides = original_overrides

  @pytest.fixture
  def mock_auth_user(self):
    """Mock authenticated user."""
    user = MagicMock()
    user.id = "test-user-123"
    user.email = "test@example.com"
    return user

  def test_backup_endpoints_require_authentication(self, client):
    """Test that backup endpoints require authentication."""
    graph_id = VALID_TEST_GRAPH_ID  # Use valid test graph ID

    # Test endpoints without authentication
    # POST /backups removed — create-backup is now at /operations/create-backup
    endpoints = [
      ("GET", f"/v1/graphs/{graph_id}/backups"),
      ("GET", f"/v1/graphs/{graph_id}/backups/stats"),
      ("DELETE", f"/v1/graphs/{graph_id}/backups/cleanup"),
      ("GET", f"/v1/graphs/{graph_id}/backups/health"),
      ("GET", f"/v1/graphs/{graph_id}/backups/metrics"),
    ]

    for method, endpoint in endpoints:
      if method == "GET":
        response = client.get(endpoint)
      elif method == "DELETE":
        response = client.delete(endpoint)
      else:
        raise ValueError(f"Unsupported HTTP method: {method}")

      # Should require authentication, not exist, or be unavailable
      assert response.status_code in [401, 403, 404, 405, 422, 503], (
        f"Expected auth/not found/unavailable error for {method} {endpoint}"
      )

  # test_create_backup_endpoint removed — POST /backups moved to
  # POST /v1/graphs/{graph_id}/operations/create-backup

  @patch("robosystems.middleware.graph.utils.MultiTenantUtils.is_shared_repository")
  @patch("robosystems.models.core.GraphUser.get_by_user_id")
  def test_list_backups_endpoint(
    self, mock_get_by_user_id, mock_is_shared, client, mock_auth_user
  ):
    """Test backup listing endpoint."""
    from robosystems.database import session
    from robosystems.middleware.auth.dependencies import get_current_user_with_graph

    # Create mock session
    mock_session = MagicMock()

    # Override the dependencies
    app.dependency_overrides[get_current_user_with_graph] = lambda: mock_auth_user
    app.dependency_overrides[session] = lambda: mock_session

    try:
      # Mock authorization checks
      mock_is_shared.return_value = False  # Not a shared repository

      # Mock user graph access - create a mock GraphUser with the test graph_id and admin role
      mock_user_graph = MagicMock()
      mock_user_graph.graph_id = VALID_TEST_GRAPH_ID
      mock_user_graph.role = "admin"  # Admin role required for backup creation
      mock_get_by_user_id.return_value = [
        mock_user_graph
      ]  # User has access to VALID_TEST_GRAPH_ID

      # Set mock user ID
      mock_auth_user.id = "test-user-123"

      # Mock GraphBackup query
      mock_backup_query = MagicMock()
      mock_backup_query.filter.return_value.order_by.return_value.all.return_value = []  # Empty backup list
      mock_session.query.return_value = mock_backup_query

      graph_id = VALID_TEST_GRAPH_ID  # Use valid test graph ID
      response = client.get(
        f"/v1/graphs/{graph_id}/backups", headers={"X-API-Key": "test-api-key"}
      )

      assert response.status_code == 200
      data = response.json()
      assert data["graph_id"] == graph_id
      assert "backups" in data
      assert "total_count" in data
    finally:
      # Reset only the specific overrides we added
      if get_current_user_with_graph in app.dependency_overrides:
        del app.dependency_overrides[get_current_user_with_graph]
      if session in app.dependency_overrides:
        del app.dependency_overrides[session]

  def test_openapi_schema_includes_backup_endpoints(self, client):
    """Test that OpenAPI schema includes backup endpoints."""
    response = client.get("/openapi.json")
    assert response.status_code == 200

    schema = response.json()
    paths = schema.get("paths", {})

    # Check for backup endpoints
    backup_paths = [p for p in paths if "/backups" in p]
    assert len(backup_paths) > 0, "No backup endpoints found in OpenAPI schema"

    # Verify operation IDs exist
    for path in backup_paths:
      for method, details in paths[path].items():
        assert "operationId" in details, (
          f"Missing operationId for {method.upper()} {path}"
        )
        assert "summary" in details, f"Missing summary for {method.upper()} {path}"

  # test_create_backup_blocked_for_shared_repository removed — POST /backups moved to
  # POST /v1/graphs/{graph_id}/operations/create-backup

  def test_list_backups_response_includes_shared_repo_fields(self, client):
    """Test that BackupListResponse model includes shared repository fields."""
    from robosystems.models.api.graphs.backups import BackupListResponse, DownloadQuota

    # Verify the response model has the expected fields for shared repositories
    assert hasattr(BackupListResponse, "model_fields")
    fields = BackupListResponse.model_fields

    # Check is_shared_repository field exists
    assert "is_shared_repository" in fields

    # Check download_quota field exists
    assert "download_quota" in fields

    # Verify DownloadQuota model structure
    quota_fields = DownloadQuota.model_fields
    assert "limit_per_month" in quota_fields
    assert "used_this_month" in quota_fields
    assert "remaining" in quota_fields
    assert "resets_at" in quota_fields
