from __future__ import annotations

import json
import os
import tempfile
import unittest
from pathlib import Path

from fastapi import HTTPException
from starlette.requests import Request

from finder_commander.app import main as agent_main


class AgentFileEndpointsTest(unittest.TestCase):
    def setUp(self) -> None:
        self.temp_dir = tempfile.TemporaryDirectory()
        self.share_root = Path(self.temp_dir.name) / "Downloads"
        self.share_root.mkdir(parents=True, exist_ok=True)
        self.outside_root = Path(self.temp_dir.name) / "Outside"
        self.outside_root.mkdir(parents=True, exist_ok=True)
        self.config_path = Path(self.temp_dir.name) / "agent.json"
        self.config_path.write_text(
            json.dumps(
                {
                    "agent_access_token": "agent-secret",
                    "client_id": "client-123",
                    "display_name": "Jan MacBook",
                    "shares": {"downloads": str(self.share_root)},
                }
            ),
            encoding="utf-8",
        )
        os.environ["FINDER_COMMANDER_REMOTE_AGENT_CONFIG"] = str(self.config_path)
        agent_main.get_runtime_config.cache_clear()

    def tearDown(self) -> None:
        os.environ.pop("FINDER_COMMANDER_REMOTE_AGENT_CONFIG", None)
        agent_main.get_runtime_config.cache_clear()
        self.temp_dir.cleanup()

    @staticmethod
    def _authorized_request() -> Request:
        return Request({"type": "http", "headers": [(b"authorization", b"Bearer agent-secret")]})

    def test_info_read_and_download_success(self) -> None:
        notes = self.share_root / "notes.md"
        notes.write_text("# title\nhello\n", encoding="utf-8")

        info_response = agent_main.api_info(self._authorized_request(), share="downloads", path="notes.md")
        self.assertEqual(info_response["kind"], "file")
        self.assertEqual(info_response["extension"], ".md")

        read_response = agent_main.api_read(self._authorized_request(), share="downloads", path="notes.md", max_bytes=4)
        self.assertTrue(read_response["truncated"])
        self.assertEqual(read_response["content"], "# ti")

        download_response = agent_main.api_download(self._authorized_request(), share="downloads", path="notes.md")
        self.assertEqual(download_response.media_type, "text/markdown")
        self.assertIn('attachment; filename="notes.md"', download_response.headers.get("content-disposition", ""))

    def test_unknown_share_and_escape_outside_root_are_rejected(self) -> None:
        outside_file = self.outside_root / "secret.txt"
        outside_file.write_text("secret", encoding="utf-8")
        (self.share_root / "escape.txt").symlink_to(outside_file)

        with self.assertRaises(HTTPException) as unknown_share:
            agent_main.api_info(self._authorized_request(), share="missing", path="notes.md")
        self.assertEqual(unknown_share.exception.status_code, 404)
        self.assertEqual(unknown_share.exception.detail["code"], "path_not_found")

        with self.assertRaises(HTTPException) as escaped:
            agent_main.api_info(self._authorized_request(), share="downloads", path="escape.txt")
        self.assertEqual(escaped.exception.status_code, 403)
        self.assertEqual(escaped.exception.detail["code"], "path_traversal_detected")


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