#!/usr/bin/env python3

from __future__ import annotations

import importlib.machinery
import importlib.util
import json
import pathlib
import subprocess
import tempfile
import unittest


ROOT = pathlib.Path(__file__).resolve().parents[2]
HELPER = ROOT / "config/dot/quickshell/scripts/panama-kdeconnect"

loader = importlib.machinery.SourceFileLoader("panama_kdeconnect", str(HELPER))
spec = importlib.util.spec_from_loader(loader.name, loader)
bridge = importlib.util.module_from_spec(spec)
loader.exec_module(bridge)


class KdeConnectBridgeTest(unittest.TestCase):
    def test_status_omits_network_and_exposes_supported_ios_actions(self) -> None:
        line = (
            "- Fixture iPhone: BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB "
            "on 192.0.2.7 via LAN (paired and reachable)"
        )
        plugins = [
            "kdeconnect_clipboard",
            "kdeconnect_findmyphone",
            "kdeconnect_ping",
            "kdeconnect_share",
            "kdeconnect_shareinputdevices",
        ]

        device = bridge.normalize_device_line(line, plugins)

        self.assertEqual(device["name"], "Fixture iPhone")
        self.assertEqual(device["type"], "phone")
        self.assertTrue(device["paired"])
        self.assertTrue(device["reachable"])
        self.assertEqual(device["actions"], ["clipboard", "ping", "ring", "share"])
        self.assertNotIn("192.0.2.7", json.dumps(device))
        self.assertNotIn("LAN", json.dumps(device))

    def test_status_parses_an_offline_paired_device(self) -> None:
        line = "- Pocket: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA (paired)"

        device = bridge.normalize_device_line(line, ["kdeconnect_share"])

        self.assertTrue(device["paired"])
        self.assertFalse(device["reachable"])
        self.assertEqual(device["actions"], ["share"])

    def test_invalid_device_id_is_rejected(self) -> None:
        with self.assertRaisesRegex(ValueError, "invalid-device"):
            bridge.validate_device_id("phone; shutdown")

    def test_send_file_requires_a_regular_file(self) -> None:
        with tempfile.TemporaryDirectory() as directory:
            with self.assertRaisesRegex(ValueError, "invalid-file"):
                bridge.validate_file(pathlib.Path(directory))

    def test_send_file_resolves_a_regular_file(self) -> None:
        with tempfile.TemporaryDirectory() as directory:
            file_path = pathlib.Path(directory) / "hello world.txt"
            file_path.write_text("fixture", encoding="utf-8")

            self.assertEqual(bridge.validate_file(file_path), file_path.resolve())

    def test_action_commands_use_separate_arguments(self) -> None:
        device_id = "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"
        self.assertEqual(
            bridge.action_command("ring", device_id),
            ["kdeconnect-cli", "-d", device_id, "--ring"],
        )
        self.assertEqual(
            bridge.action_command("clipboard", device_id),
            ["kdeconnect-cli", "-d", device_id, "--send-clipboard"],
        )

    def test_unknown_action_is_rejected(self) -> None:
        with self.assertRaisesRegex(ValueError, "unsupported-action"):
            bridge.action_command(
                "unlock",
                "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB",
            )

    def test_busctl_plugin_output_is_normalized(self) -> None:
        output = (
            'as 5 "kdeconnect_ping" "kdeconnect_share" '
            '"kdeconnect_clipboard" "kdeconnect_findmyphone" "unrelated"\n'
        )

        self.assertEqual(
            bridge.parse_loaded_plugins(output),
            [
                "kdeconnect_ping",
                "kdeconnect_share",
                "kdeconnect_clipboard",
                "kdeconnect_findmyphone",
                "unrelated",
            ],
        )

    def test_offline_device_falls_back_to_supported_plugins(self) -> None:
        def runner(command: list[str], **_kwargs: object) -> subprocess.CompletedProcess[str]:
            member = command[-1]
            if member == "loadedPlugins":
                return subprocess.CompletedProcess(command, 0, "as 0\n", "")
            if member == "supportedPlugins":
                return subprocess.CompletedProcess(
                    command,
                    0,
                    'as 3 "kdeconnect_share" "kdeconnect_clipboard" "kdeconnect_findmyphone"\n',
                    "",
                )
            raise AssertionError(command)

        self.assertEqual(
            bridge.device_plugins(
                "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB",
                runner,
            ),
            [
                "kdeconnect_share",
                "kdeconnect_clipboard",
                "kdeconnect_findmyphone",
            ],
        )


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