# ... (same header as before)

import os

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

import sys
from pathlib import Path
from unittest.mock import AsyncMock, MagicMock, patch

import pytest
from fastapi import FastAPI
from fastapi.testclient import TestClient

_src = str(Path(__file__).resolve().parent.parent.parent / "src")
if _src not in sys.path:
    sys.path.insert(0, _src)


def _make_client(overrides: dict | None = None) -> TestClient:
    from src.api.routes.tasks import router
    from src.core.database import get_db
    from src.dependencies import get_config_manager, get_current_user, get_task_manager
    from src.schemas.auth import User, RoleSchema

    app = FastAPI()
    app.include_router(router, prefix="/api/tasks")

    mock_user = User(
        id="admin-1", username="admin", email="admin@x.com",
        auth_source="LOCAL",
        created_at=__import__("datetime").datetime.now(),
        roles=[RoleSchema(id="r1", name="Admin", description="", permissions=[])],
    )

    app.dependency_overrides[get_db] = lambda: MagicMock()
    app.dependency_overrides[get_current_user] = lambda: mock_user
    app.dependency_overrides[get_config_manager] = lambda: MagicMock()
    app.dependency_overrides[get_task_manager] = lambda: MagicMock()
    if overrides:
        for dep, fn in overrides.items():
            app.dependency_overrides[dep] = fn
    return TestClient(app)


# ── create_task ──

class TestCreateTask:
    """POST /api/tasks"""

    def test_success(self):
        mock_tm = MagicMock()
        from src.core.task_manager import Task
        mock_task = MagicMock(spec=Task)
        mock_task.id = "task-1"
        mock_task.plugin_id = "backup"
        mock_task.status = "PENDING"
        mock_task.params = {}
        mock_task.created_at = None
        mock_task.user_id = "admin"
        mock_task.input_request = None
        mock_tm.create_task = AsyncMock(return_value=mock_task)

        from src.dependencies import get_task_manager
        client = _make_client({get_task_manager: lambda: mock_tm})
        resp = client.post("/api/tasks", json={"plugin_id": "superset-backup", "params": {"dashboard_id": 42}})
        assert resp.status_code == 201

    def test_deprecated_llm_validation_returns_400(self):
        client = _make_client()
        resp = client.post("/api/tasks", json={
            "plugin_id": "llm_dashboard_validation",
            "params": {"dashboard_ids": ["dash-1"], "environment_id": "env-1"},
        })
        assert resp.status_code == 400

    def test_value_error(self):
        mock_tm = MagicMock()
        mock_tm.create_task = AsyncMock(side_effect=ValueError("Plugin not found"))

        from src.dependencies import get_task_manager
        client = _make_client({get_task_manager: lambda: mock_tm})
        resp = client.post("/api/tasks", json={"plugin_id": "unknown", "params": {}})
        assert resp.status_code == 404


# ── list_tasks ──

class TestListTasks:
    """GET /api/tasks"""

    def test_success(self):
        mock_tm = MagicMock()
        mock_tm.get_tasks.return_value = []

        from src.dependencies import get_task_manager
        client = _make_client({get_task_manager: lambda: mock_tm})
        resp = client.get("/api/tasks")
        assert resp.status_code == 200

    def test_with_filters(self):
        mock_tm = MagicMock()
        mock_tm.get_tasks.return_value = []

        from src.dependencies import get_task_manager
        client = _make_client({get_task_manager: lambda: mock_tm})
        resp = client.get("/api/tasks?limit=5&offset=10&status=RUNNING&completed_only=true")
        assert resp.status_code == 200

    def test_with_plugin_ids(self):
        mock_tm = MagicMock()
        mock_tm.get_tasks.return_value = []

        from src.dependencies import get_task_manager
        client = _make_client({get_task_manager: lambda: mock_tm})
        resp = client.get("/api/tasks?plugin_id=backup&plugin_id=migration")
        assert resp.status_code == 200

    def test_with_task_type(self):
        mock_tm = MagicMock()
        mock_tm.get_tasks.return_value = []

        from src.dependencies import get_task_manager
        client = _make_client({get_task_manager: lambda: mock_tm})
        resp = client.get("/api/tasks?task_type=llm_validation")
        assert resp.status_code == 200

    def test_unsupported_task_type(self):
        client = _make_client()
        resp = client.get("/api/tasks?task_type=unsupported")
        assert resp.status_code == 400


# ── get_task ──

class TestGetTask:
    """GET /api/tasks/{task_id}"""

    def test_success(self):
        mock_tm = MagicMock()
        from src.core.task_manager import Task
        mock_task = MagicMock(spec=Task)
        mock_task.id = "task-123"
        mock_task.plugin_id = "backup"
        mock_task.status = "PENDING"
        mock_task.params = {}
        mock_task.created_at = None
        mock_task.user_id = "admin"
        mock_task.input_request = None
        mock_tm.get_task.return_value = mock_task

        from src.dependencies import get_task_manager
        client = _make_client({get_task_manager: lambda: mock_tm})
        resp = client.get("/api/tasks/task-123")
        assert resp.status_code == 200
        assert resp.json()["id"] == "task-123"

    def test_not_found(self):
        mock_tm = MagicMock()
        mock_tm.get_task.return_value = None

        from src.dependencies import get_task_manager
        client = _make_client({get_task_manager: lambda: mock_tm})
        resp = client.get("/api/tasks/unknown")
        assert resp.status_code == 404


# ── get_task_logs ──

class TestGetTaskLogs:
    """GET /api/tasks/{task_id}/logs"""

    def test_success(self):
        mock_tm = MagicMock()
        mock_tm.get_task.return_value = MagicMock(id="task-123")
        mock_tm.get_task_logs.return_value = [MagicMock(level="INFO", message="test", timestamp=None, source="test")]

        from src.dependencies import get_task_manager
        client = _make_client({get_task_manager: lambda: mock_tm})
        resp = client.get("/api/tasks/task-123/logs")
        assert resp.status_code == 200

    def test_with_filters(self):
        mock_tm = MagicMock()
        mock_tm.get_task.return_value = MagicMock(id="task-123")

        from src.dependencies import get_task_manager
        client = _make_client({get_task_manager: lambda: mock_tm})
        resp = client.get("/api/tasks/task-123/logs?level=INFO&source=worker&search=error&offset=0&limit=50")
        assert resp.status_code == 200

    def test_task_not_found(self):
        mock_tm = MagicMock()
        mock_tm.get_task.return_value = None

        from src.dependencies import get_task_manager
        client = _make_client({get_task_manager: lambda: mock_tm})
        resp = client.get("/api/tasks/unknown/logs")
        assert resp.status_code == 404


# ── get_task_log_stats ──

class TestGetTaskLogStats:
    """GET /api/tasks/{task_id}/logs/stats"""

    def test_success_with_logstats(self):
        from src.core.task_manager.models import LogStats
        mock_tm = MagicMock()
        mock_tm.get_task.return_value = MagicMock(id="task-123")
        mock_tm.get_task_log_stats.return_value = LogStats(total_count=5, by_level={"INFO": 3}, by_source={"worker": 5})

        from src.dependencies import get_task_manager
        client = _make_client({get_task_manager: lambda: mock_tm})
        resp = client.get("/api/tasks/task-123/logs/stats")
        assert resp.status_code == 200
        assert resp.json()["total_count"] == 5

    def test_success_with_dict_payload(self):
        mock_tm = MagicMock()
        mock_tm.get_task.return_value = MagicMock(id="task-123")
        mock_tm.get_task_log_stats.return_value = {"total_count": 3, "by_level": {"INFO": 2}, "by_source": {"worker": 3}}

        from src.dependencies import get_task_manager
        client = _make_client({get_task_manager: lambda: mock_tm})
        resp = client.get("/api/tasks/task-123/logs/stats")
        assert resp.status_code == 200

    def test_success_with_flat_dict(self):
        mock_tm = MagicMock()
        mock_tm.get_task.return_value = MagicMock(id="task-123")
        mock_tm.get_task_log_stats.return_value = {"INFO": 3, "ERROR": 1}

        from src.dependencies import get_task_manager
        client = _make_client({get_task_manager: lambda: mock_tm})
        resp = client.get("/api/tasks/task-123/logs/stats")
        assert resp.status_code == 200
        assert resp.json()["total_count"] == 4

    def test_task_not_found(self):
        mock_tm = MagicMock()
        mock_tm.get_task.return_value = None

        from src.dependencies import get_task_manager
        client = _make_client({get_task_manager: lambda: mock_tm})
        resp = client.get("/api/tasks/unknown/logs/stats")
        assert resp.status_code == 404


# ── get_task_log_sources ──

class TestGetTaskLogSources:
    """GET /api/tasks/{task_id}/logs/sources"""

    def test_success(self):
        mock_tm = MagicMock()
        mock_tm.get_task.return_value = MagicMock(id="task-123")
        mock_tm.get_task_log_sources.return_value = ["worker", "api"]

        from src.dependencies import get_task_manager
        client = _make_client({get_task_manager: lambda: mock_tm})
        resp = client.get("/api/tasks/task-123/logs/sources")
        assert resp.status_code == 200
        assert resp.json() == ["worker", "api"]

    def test_task_not_found(self):
        mock_tm = MagicMock()
        mock_tm.get_task.return_value = None

        from src.dependencies import get_task_manager
        client = _make_client({get_task_manager: lambda: mock_tm})
        resp = client.get("/api/tasks/unknown/logs/sources")
        assert resp.status_code == 404


# ── resolve_task ──

class TestResolveTask:
    """POST /api/tasks/{task_id}/resolve"""

    def test_success(self):
        mock_tm = MagicMock()
        mock_tm.resolve_task = AsyncMock()
        from src.core.task_manager import Task
        mock_task = MagicMock(spec=Task)
        mock_task.id = "task-123"
        mock_tm.get_task.return_value = mock_task

        from src.dependencies import get_task_manager
        client = _make_client({get_task_manager: lambda: mock_tm})
        resp = client.post("/api/tasks/task-123/resolve", json={"resolution_params": {"key": "value"}})
        assert resp.status_code == 200

    def test_value_error(self):
        mock_tm = MagicMock()
        mock_tm.resolve_task = AsyncMock(side_effect=ValueError("Cannot resolve"))

        from src.dependencies import get_task_manager
        client = _make_client({get_task_manager: lambda: mock_tm})
        resp = client.post("/api/tasks/task-123/resolve", json={"resolution_params": {}})
        assert resp.status_code == 400


# ── resume_task ──

class TestResumeTask:
    """POST /api/tasks/{task_id}/resume"""

    def test_success(self):
        mock_tm = MagicMock()
        mock_tm.resume_task_with_password = MagicMock()
        from src.core.task_manager import Task
        mock_task = MagicMock(spec=Task)
        mock_task.id = "task-123"
        mock_tm.get_task.return_value = mock_task

        from src.dependencies import get_task_manager
        client = _make_client({get_task_manager: lambda: mock_tm})
        resp = client.post("/api/tasks/task-123/resume", json={"passwords": {"db": "pwd"}})
        assert resp.status_code == 200

    def test_value_error(self):
        mock_tm = MagicMock()
        mock_tm.resume_task_with_password = MagicMock(side_effect=ValueError("Cannot resume"))

        from src.dependencies import get_task_manager
        client = _make_client({get_task_manager: lambda: mock_tm})
        resp = client.post("/api/tasks/task-123/resume", json={"passwords": {}})
        assert resp.status_code == 400


# ── clear_tasks ──

class TestClearTasks:
    """DELETE /api/tasks"""

    def test_success(self):
        mock_tm = MagicMock()

        from src.dependencies import get_task_manager
        client = _make_client({get_task_manager: lambda: mock_tm})
        resp = client.delete("/api/tasks")
        assert resp.status_code == 204

    def test_with_status(self):
        mock_tm = MagicMock()

        from src.dependencies import get_task_manager
        client = _make_client({get_task_manager: lambda: mock_tm})
        resp = client.delete("/api/tasks?status=COMPLETED")
        assert resp.status_code == 204
# #endregion Test.Api.Tasks
