"""
REAL integration tests for desktop system RPC functions.

These make actual HTTP requests to a running Django server.
No RequestFactory, no mocks, no shortcuts.
"""

import json
import os
import platform
from pathlib import Path

from django.test import LiveServerTestCase
from urllib.request import urlopen, Request


class RealHTTPMixin:
    """Makes real HTTP requests to the live server."""

    def _session_init(self):
        """Hit /session/ to get CSRF cookie, like mizanProvider does."""
        url = f"{self.live_server_url}/api/mizan/session/"
        req = Request(url)
        resp = urlopen(req)
        # Extract csrftoken from Set-Cookie header
        cookies = resp.headers.get_all("Set-Cookie") or []
        for cookie in cookies:
            if "csrftoken=" in cookie:
                self._csrf_token = cookie.split("csrftoken=")[1].split(";")[0]
                self._cookies = f"csrftoken={self._csrf_token}"
                return
        self._csrf_token = None
        self._cookies = ""

    def _call(self, fn: str, args: dict | None = None):
        """Make a real POST to /api/mizan/call/ with CSRF token."""
        url = f"{self.live_server_url}/api/mizan/call/"
        body = json.dumps({"fn": fn, "args": args or {}}).encode()
        req = Request(url, data=body, method="POST")
        req.add_header("Content-Type", "application/json")
        if self._csrf_token:
            req.add_header("X-CSRFToken", self._csrf_token)
        if self._cookies:
            req.add_header("Cookie", self._cookies)
        resp = urlopen(req)
        return json.loads(resp.read())


class SystemInfoTests(RealHTTPMixin, LiveServerTestCase):
    """system_info over real HTTP."""

    def setUp(self):
        self._session_init()

    def test_system_info_returns_os_data(self):
        data = self._call("system_info")

        self.assertFalse(data["error"])
        self.assertEqual(data["data"]["os_name"], platform.system())
        self.assertEqual(data["data"]["hostname"], platform.node())
        self.assertGreater(data["data"]["cpu_count"], 0)

    def test_system_info_returns_paths(self):
        data = self._call("system_info")

        self.assertFalse(data["error"])
        self.assertEqual(data["data"]["home_dir"], str(Path.home()))
        self.assertEqual(data["data"]["cwd"], os.getcwd())

    def test_disk_usage(self):
        data = self._call("disk_usage", {"path": "/"})

        self.assertFalse(data["error"])
        self.assertGreater(data["data"]["total_gb"], 0)
        self.assertGreater(data["data"]["free_gb"], 0)
        self.assertGreaterEqual(data["data"]["percent_used"], 0)
        self.assertLessEqual(data["data"]["percent_used"], 100)

    def test_app_info(self):
        data = self._call("app_info")

        self.assertFalse(data["error"])
        self.assertEqual(data["data"]["app_name"], "mizan Desktop")
        self.assertGreater(data["data"]["uptime_seconds"], 0)


class FileSystemTests(RealHTTPMixin, LiveServerTestCase):
    """File system RPC over real HTTP."""

    def setUp(self):
        self._session_init()
        self.test_dir = Path.home() / ".mizan-test"
        self.test_dir.mkdir(exist_ok=True)

    def tearDown(self):
        import shutil

        if self.test_dir.exists():
            shutil.rmtree(self.test_dir)

    def test_list_files_home(self):
        data = self._call("list_files", {"directory": "~"})

        self.assertFalse(data["error"])
        self.assertEqual(data["data"]["directory"], str(Path.home()))
        self.assertIsInstance(data["data"]["entries"], list)

    def test_list_files_root_has_no_parent(self):
        data = self._call("list_files", {"directory": "/"})

        self.assertFalse(data["error"])
        self.assertIsNone(data["data"]["parent"])

    def test_write_and_read_file(self):
        """Full round-trip over real HTTP: write, read back, verify."""
        test_path = str(self.test_dir / "test-note.txt")
        test_content = "Hello from a REAL HTTP integration test!"

        # Write
        write_data = self._call(
            "write_file", {"path": test_path, "content": test_content}
        )
        self.assertFalse(write_data["error"])
        self.assertEqual(write_data["data"]["path"], test_path)

        # Read back
        read_data = self._call("read_file", {"path": test_path})
        self.assertFalse(read_data["error"])
        self.assertEqual(read_data["data"]["content"], test_content)

    def test_write_outside_home_rejected(self):
        """Server should reject writes outside home directory."""
        from urllib.error import HTTPError

        try:
            data = self._call(
                "write_file", {"path": "/tmp/escape.txt", "content": "nope"}
            )
            # If we get here, check the response has an error
            self.assertTrue(data["error"])
            self.assertEqual(data["code"], "FORBIDDEN")
        except HTTPError as e:
            # 403 is also acceptable
            self.assertEqual(e.code, 403)

    def test_delete_file(self):
        test_path = str(self.test_dir / "to-delete.txt")
        (self.test_dir / "to-delete.txt").write_text("delete me")

        data = self._call("delete_file", {"path": test_path})
        self.assertFalse(data["error"])
        self.assertTrue(data["data"]["deleted"])
        self.assertFalse(Path(test_path).exists())

    def test_file_entries_have_metadata(self):
        (self.test_dir / "metadata-test.txt").write_text("hello")

        data = self._call("list_files", {"directory": str(self.test_dir)})
        self.assertFalse(data["error"])
        self.assertGreater(len(data["data"]["entries"]), 0)

        entry = data["data"]["entries"][0]
        self.assertIn("name", entry)
        self.assertIn("path", entry)
        self.assertIn("is_dir", entry)
        self.assertIn("size", entry)
        self.assertIn("modified", entry)
