#region TestLlmProviderDelete [C:3] [TYPE Module] [SEMANTICS test, llm, provider, delete, validation-policy, 409]
# @BRIEF Tests for FR-058: LLM provider DELETE is blocked when active ValidationPolicy references exist.
# @RELATION BINDS_TO -> [LlmRoutes]
# @RELATION DEPENDS_ON -> [EXT:FastAPI:TestClient]
# @TEST_EDGE: active_tasks_block_delete -> 409 with blocking_tasks list when provider has active policies
# @TEST_EDGE: provider_not_found -> 404 when provider does not exist
# @TEST_EDGE: no_active_tasks -> 204 when no policies reference the provider
# @INVARIANT Provider with active ValidationPolicy.is_active=True references cannot be deleted (FR-058)

import os

os.environ.setdefault("SECRET_KEY", "test-secret-key-for-testing")
os.environ.setdefault("AUTH_DATABASE_URL", "sqlite:///:memory:test_auth_provider_delete")
os.environ.setdefault("DATABASE_URL", "sqlite:///:memory:test_main_provider_delete")
os.environ.setdefault("DEV_MODE", "true")

import pytest
from types import SimpleNamespace
from unittest.mock import MagicMock, patch

from fastapi.testclient import TestClient
from sqlalchemy.orm import Session

from src.app import app
from src.core.database import get_db
from src.dependencies import get_current_user
from src.models.auth import User

# ── Shared mocks ───────────────────────────────────────────────────────

mock_user = MagicMock(spec=User)
mock_user.username = "admin"
mock_user.roles = []


@pytest.fixture(autouse=True)
def mock_auth():
    """Provide authenticated admin user for all tests in this module."""
    mock_user.roles = []
    app.dependency_overrides[get_current_user] = lambda: mock_user
    yield
    app.dependency_overrides.clear()


client = TestClient(app)


def _make_mock_db():
    """Build a mock DB session that controls ValidationPolicy query results.

    Returns (mock_db, policy_list) where policy_list can be mutated
    to control whether the provider has active tasks.

    Uses SimpleNamespace instead of MagicMock for policy objects to
    ensure deterministic attribute access without MagicMock interference.
    """
    policy_list: list[SimpleNamespace] = []
    mock_db = MagicMock(spec=Session)

    # Wire query().filter().all() to return policy_list
    mock_query = MagicMock()
    mock_db.query.return_value = mock_query
    mock_query.filter.return_value = mock_query
    mock_query.all.return_value = policy_list

    return mock_db, policy_list


#region test_delete_provider_with_active_tasks_returns_409 [C:2] [TYPE Function]
# @BRIEF T062: Delete provider referenced by active ValidationPolicy → 409 with blocking_tasks.
# @TEST_INVARIANT provider_active_task_block -> VERIFIED_BY: test_delete_provider_with_active_tasks_returns_409
# @RATIONALE FR-058: providers with active task references must be protected from
#            accidental deletion. The route queries ValidationPolicy.is_active == True
#            and returns blocking_tasks names in the error detail.
def test_delete_provider_with_active_tasks_returns_409(mock_auth):  # noqa: ARG001
    """DELETE /api/llm/providers/{id} with active validation tasks → 409 + blocking_tasks."""
    mock_db, policy_list = _make_mock_db()

    # Seed one active validation task referencing the provider
    policy_list.append(
        SimpleNamespace(id="policy-1", name="Scheduled LLM Check")
    )

    app.dependency_overrides[get_db] = lambda: mock_db
    try:
        response = client.delete("/api/llm/providers/provider-multi-1")
        assert response.status_code == 409
        detail = response.json()["detail"]
        assert "error" in detail
        assert "active validation task" in detail["error"].lower()
        blocking_tasks = detail.get("blocking_tasks", [])
        assert len(blocking_tasks) == 1
        assert blocking_tasks[0]["name"] == "Scheduled LLM Check"
        assert blocking_tasks[0]["id"] == "policy-1"
    finally:
        app.dependency_overrides.pop(get_db, None)
#endregion test_delete_provider_with_active_tasks_returns_409


#region test_delete_provider_with_multiple_active_tasks [C:2] [TYPE Function]
# @BRIEF T062 variant: multiple active tasks all appear in blocking_tasks list.
def test_delete_provider_with_multiple_active_tasks(mock_auth):  # noqa: ARG001
    """DELETE with 3 active tasks returns all in blocking_tasks."""
    mock_db, policy_list = _make_mock_db()

    policy_list.extend([
        SimpleNamespace(id="p-1", name="Weekday Check"),
        SimpleNamespace(id="p-2", name="Weekend Check"),
        SimpleNamespace(id="p-3", name="Nightly Check"),
    ])

    app.dependency_overrides[get_db] = lambda: mock_db
    try:
        response = client.delete("/api/llm/providers/provider-multi-2")
        assert response.status_code == 409
        detail = response.json()["detail"]
        assert len(detail["blocking_tasks"]) == 3
        names = {t["name"] for t in detail["blocking_tasks"]}
        assert names == {"Weekday Check", "Weekend Check", "Nightly Check"}
    finally:
        app.dependency_overrides.pop(get_db, None)
#endregion test_delete_provider_with_multiple_active_tasks


#region test_delete_provider_no_active_tasks_succeeds [C:2] [TYPE Function]
# @BRIEF T062 variant: no active policies → 204 deletion success.
def test_delete_provider_no_active_tasks_succeeds(mock_auth):  # noqa: ARG001
    """DELETE with no active ValidationPolicy → 204."""
    mock_db, policy_list = _make_mock_db()
    # Empty policy_list — no active tasks
    policy_list.clear()

    # Mock the provider service to succeed
    mock_provider_service = MagicMock()
    mock_provider_service.delete_provider.return_value = True

    with patch("src.api.routes.llm.LLMProviderService") as mock_provider_svc:
        mock_provider_svc.return_value = mock_provider_service
        app.dependency_overrides[get_db] = lambda: mock_db
        try:
            response = client.delete("/api/llm/providers/provider-no-tasks")
            assert response.status_code == 204
        finally:
            app.dependency_overrides.pop(get_db, None)
#endregion test_delete_provider_no_active_tasks_succeeds


#region test_delete_provider_not_found_returns_404 [C:2] [TYPE Function]
# @BRIEF T062 variant: nonexistent provider → 404.
def test_delete_provider_not_found_returns_404(mock_auth):  # noqa: ARG001
    """DELETE on nonexistent provider returns 404."""
    mock_db, policy_list = _make_mock_db()
    policy_list.clear()

    mock_provider_service = MagicMock()
    mock_provider_service.delete_provider.return_value = False

    with patch("src.api.routes.llm.LLMProviderService") as mock_provider_svc:
        mock_provider_svc.return_value = mock_provider_service
        app.dependency_overrides[get_db] = lambda: mock_db
        try:
            response = client.delete("/api/llm/providers/nonexistent-provider")
            assert response.status_code == 404
        finally:
            app.dependency_overrides.pop(get_db, None)
#endregion test_delete_provider_not_found_returns_404

#endregion TestLlmProviderDelete
