from __future__ import annotations

import asyncio
import sys
import tempfile
import unittest
from pathlib import Path

import httpx

sys.path.insert(0, str(Path(__file__).resolve().parents[3]))

from backend.app.dependencies import get_browse_service
from backend.app.fs.filesystem_adapter import FilesystemAdapter
from backend.app.main import app
from backend.app.security.path_guard import PathGuard
from backend.app.services.browse_service import BrowseService


class BrowseApiErrorsGoldenTest(unittest.TestCase):
    def setUp(self) -> None:
        self.temp_dir = tempfile.TemporaryDirectory()
        self.root = Path(self.temp_dir.name) / "root"
        self.root.mkdir(parents=True, exist_ok=True)
        (self.root / "a.txt").write_text("a", encoding="utf-8")

        service = BrowseService(
            path_guard=PathGuard({"storage1": str(self.root)}),
            filesystem=FilesystemAdapter(),
        )
        async def _override_browse_service() -> BrowseService:
            return service

        app.dependency_overrides[get_browse_service] = _override_browse_service

    def tearDown(self) -> None:
        app.dependency_overrides.clear()
        self.temp_dir.cleanup()

    def _get(self, path: str) -> httpx.Response:
        async def _run() -> httpx.Response:
            transport = httpx.ASGITransport(app=app)
            async with httpx.AsyncClient(transport=transport, base_url="http://testserver") as client:
                return await client.get("/api/browse", params={"path": path})

        return asyncio.run(_run())

    def test_invalid_root_alias_error_shape(self) -> None:
        response = self._get("unknown/path")

        self.assertEqual(response.status_code, 403)
        self.assertEqual(
            response.json(),
            {
                "error": {
                    "code": "invalid_root_alias",
                    "message": "Unknown root alias",
                    "details": {"path": "unknown/path"},
                }
            },
        )

    def test_traversal_error_shape(self) -> None:
        response = self._get("storage1/../etc")

        self.assertEqual(response.status_code, 403)
        self.assertEqual(
            response.json(),
            {
                "error": {
                    "code": "path_traversal_detected",
                    "message": "Path traversal is not allowed",
                    "details": {"path": "storage1/../etc"},
                }
            },
        )

    def test_not_found_error_shape(self) -> None:
        response = self._get("storage1/missing")

        self.assertEqual(response.status_code, 404)
        self.assertEqual(
            response.json(),
            {
                "error": {
                    "code": "path_not_found",
                    "message": "Requested path was not found",
                    "details": {"path": "storage1/missing"},
                }
            },
        )

    def test_type_conflict_error_shape(self) -> None:
        response = self._get("storage1/a.txt")

        self.assertEqual(response.status_code, 409)
        self.assertEqual(
            response.json(),
            {
                "error": {
                    "code": "path_type_conflict",
                    "message": "Requested path is not a directory",
                    "details": {"path": "storage1/a.txt"},
                }
            },
        )


if __name__ == "__main__":
    unittest.main()
