# #region Test.Api.ReportsRoutes [C:3] [TYPE Module] [SEMANTICS test,reports,api]
# @BRIEF Tests for reports.py — list reports and get report detail.
# @RELATION BINDS_TO -> [ReportsRouter]
# @TEST_EDGE: parse_invalid_task_type -> 400
# @TEST_EDGE: parse_invalid_status -> 400
# @TEST_EDGE: general_query_exception -> 400
# @TEST_EDGE: report_not_found -> 404

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")

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

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, raise_server_exceptions: bool = True) -> TestClient:
    from src.api.routes.reports import router
    from src.dependencies import get_clean_release_repository, get_task_manager, get_current_user, has_permission
    from src.schemas.auth import User, RoleSchema

    app = FastAPI()
    app.include_router(router)

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

    defaults = {
        get_task_manager: lambda: MagicMock(),
        get_clean_release_repository: lambda: MagicMock(),
        get_current_user: lambda: mock_user,
        has_permission: lambda *a, **kw: lambda: None,
    }
    if overrides:
        defaults.update(overrides)
    for dep, mock_fn in defaults.items():
        app.dependency_overrides[dep] = mock_fn
    return TestClient(app, raise_server_exceptions=raise_server_exceptions)


# ── _parse_csv_enum_list ──

class TestParseCsvEnumList:
    """_parse_csv_enum_list — parse comma-separated values into enum list."""

    def test_none_returns_empty(self):
        from src.api.routes.reports import _parse_csv_enum_list
        from src.models.report import TaskType
        assert _parse_csv_enum_list(None, TaskType, "task_types") == []

    def test_empty_string_returns_empty(self):
        from src.api.routes.reports import _parse_csv_enum_list
        from src.models.report import TaskType
        assert _parse_csv_enum_list("", TaskType, "task_types") == []

    def test_valid_values_parsed(self):
        from src.api.routes.reports import _parse_csv_enum_list
        from src.models.report import TaskType
        result = _parse_csv_enum_list("backup, migration", TaskType, "task_types")
        assert TaskType.BACKUP in result
        assert TaskType.MIGRATION in result

    def test_invalid_values_raise_400(self):
        from fastapi import HTTPException
        from src.api.routes.reports import _parse_csv_enum_list
        from src.models.report import TaskType
        with pytest.raises(HTTPException) as exc:
            _parse_csv_enum_list("INVALID_TYPE", TaskType, "task_types")
        assert exc.value.status_code == 400


# ── list_reports ──

class TestListReports:
    """GET /api/reports"""

    def test_list_success(self):
        from src.models.report import ReportCollection, ReportQuery
        with patch("src.api.routes.reports.ReportsService") as MockService:
            instance = MockService.return_value
            instance.list_reports.return_value = ReportCollection(
                items=[], total=0, page=1, page_size=20, has_next=False,
                applied_filters=ReportQuery(),
            )
            client = _make_client()
            resp = client.get("/api/reports?page=1&page_size=20")
        assert resp.status_code == 200
        data = resp.json()
        assert "items" in data
        assert "total" in data

    def test_list_with_filters(self):
        from src.models.report import ReportCollection, ReportQuery
        with patch("src.api.routes.reports.ReportsService") as MockService:
            instance = MockService.return_value
            instance.list_reports.return_value = ReportCollection(
                items=[], total=0, page=1, page_size=20, has_next=False,
                applied_filters=ReportQuery(search="test", sort_by="updated_at", sort_order="asc"),
            )
            client = _make_client()
            resp = client.get("/api/reports?page=1&page_size=20&search=test&sort_by=updated_at&sort_order=asc")
        assert resp.status_code == 200

    def test_list_invalid_task_type_400(self):
        client = _make_client()
        resp = client.get("/api/reports?task_types=INVALID")
        assert resp.status_code == 400

    def test_list_invalid_status_400(self):
        client = _make_client()
        resp = client.get("/api/reports?statuses=INVALID")
        assert resp.status_code == 400

    def test_list_service_exception_500(self):
        with patch("src.api.routes.reports.ReportsService") as MockService:
            instance = MockService.return_value
            instance.list_reports.side_effect = ValueError("Internal error")
            client = _make_client(raise_server_exceptions=False)
            resp = client.get("/api/reports?page=1&page_size=20")
        # Exception from service call is outside try-except -> 500
        assert resp.status_code == 500

    def test_list_invalid_page_size_400(self):
        mock_task_manager = MagicMock()
        mock_clean_repo = MagicMock()

        from src.dependencies import get_task_manager, get_clean_release_repository
        client = _make_client({
            get_task_manager: lambda: mock_task_manager,
            get_clean_release_repository: lambda: mock_clean_repo,
        })
        # page_size=0 is rejected by Query(ge=1) -> FastAPI 422
        resp = client.get("/api/reports?page_size=0")
        assert resp.status_code == 422


# ── get_report_detail ──

class TestGetReportDetail:
    """GET /api/reports/{report_id}"""

    def test_detail_success(self):
        from src.models.report import ReportDetailView, TaskReport, ReportStatus, TaskType
        dt = __import__("datetime").datetime.now()
        with patch("src.api.routes.reports.ReportsService") as MockService:
            instance = MockService.return_value
            instance.get_report_detail.return_value = ReportDetailView(
                report=TaskReport(
                    report_id="report-1",
                    task_id="task-1",
                    task_type=TaskType.BACKUP,
                    status=ReportStatus.SUCCESS,
                    updated_at=dt,
                    summary="Backup completed successfully",
                ),
                diagnostics=None,
                next_actions=[],
            )
            client = _make_client()
            resp = client.get("/api/reports/report-1")
        assert resp.status_code == 200
        data = resp.json()
        assert data["report"]["report_id"] == "report-1"

    def test_detail_not_found(self):
        mock_task_manager = MagicMock()
        mock_clean_repo = MagicMock()

        from src.dependencies import get_task_manager, get_clean_release_repository
        client = _make_client({
            get_task_manager: lambda: mock_task_manager,
            get_clean_release_repository: lambda: mock_clean_repo,
        })

        with patch("src.api.routes.reports.ReportsService") as MockService:
            instance = MockService.return_value
            instance.get_report_detail.return_value = None
            resp = client.get("/api/reports/report-missing")
        assert resp.status_code == 404
        assert "REPORT_NOT_FOUND" in resp.text
# #endregion Test.Api.ReportsRoutes
