from unittest.mock import Mock

import pytest

from fenrirscreenreader.core.commandManager import CommandManager
from fenrirscreenreader.core.settingsManager import SettingsManager


def write_script(path):
    path.write_text("#!/bin/sh\n", encoding="utf-8")
    path.chmod(0o755)


def build_command_environment(local_path, system_path):
    settings_manager = Mock()
    settings_manager.get_user_script_path.return_value = str(local_path)
    settings_manager.get_setting.return_value = str(system_path)
    valid_keys = {
        "KEY_A",
        "KEY_B",
        "KEY_C",
        "KEY_D",
        "KEY_E",
        "KEY_SHIFT",
        "KEY_SCRIPT",
        "KEY_U",
        "KEY_X",
    }

    return {
        "commands": {"commands": {}},
        "commandsIgnore": {"commands": {}},
        "bindings": {
            str([1, sorted(["KEY_C", "KEY_SCRIPT"])]): "EXISTING"
        },
        "rawBindings": {},
        "general": {"curr_user": "Username"},
        "runtime": {
            "SettingsManager": settings_manager,
            "DebugManager": Mock(write_debug_out=Mock()),
            "InputManager": Mock(
                is_valid_key=Mock(side_effect=lambda key: key in valid_keys)
            ),
        },
    }


@pytest.mark.unit
def test_local_scripts_load_before_non_conflicting_system_scripts(tmp_path):
    local_path = tmp_path / "local"
    system_path = tmp_path / "system"
    local_path.mkdir()
    system_path.mkdir()
    write_script(local_path / "local_only__-__KEY_A")
    write_script(local_path / "same_name__-__KEY_B")
    write_script(system_path / "same_name__-__KEY_D")
    write_script(system_path / "system_only__-__KEY_E")

    env = build_command_environment(local_path, system_path)
    command_manager = CommandManager()
    command_manager.initialize = lambda environment: None
    command_manager.env = env

    command_manager.load_script_commands()

    commands = env["commands"]["commands"]
    assert "LOCAL_ONLY__-__KEY_A" in commands
    assert "SYSTEM_ONLY__-__KEY_E" in commands
    assert commands["SAME_NAME__-__KEY_B"].script_path == str(
        local_path / "same_name__-__KEY_B"
    )
    assert "SAME_NAME__-__KEY_D" not in commands


@pytest.mark.unit
def test_system_scripts_skip_existing_shortcut_bindings(tmp_path):
    local_path = tmp_path / "local"
    system_path = tmp_path / "system"
    local_path.mkdir()
    system_path.mkdir()
    write_script(system_path / "conflicting_key__-__KEY_C")
    write_script(system_path / "system_only__-__KEY_E")

    env = build_command_environment(local_path, system_path)
    command_manager = CommandManager()
    command_manager.env = env

    command_manager.load_script_commands()

    commands = env["commands"]["commands"]
    assert "CONFLICTING_KEY__-__KEY_C" not in commands
    assert "SYSTEM_ONLY__-__KEY_E" in commands


@pytest.mark.unit
def test_same_directory_script_variants_load_multiple_shortcuts(tmp_path):
    local_path = tmp_path / "local"
    system_path = tmp_path / "system"
    local_path.mkdir()
    system_path.mkdir()
    write_script(system_path / "musicplayer__-__KEY_SHIFT__+__KEY_U.sh")
    write_script(system_path / "musicplayer__-__KEY_SHIFT__+__KEY_X.sh")

    env = build_command_environment(local_path, system_path)
    command_manager = CommandManager()
    command_manager.env = env

    command_manager.load_script_commands()

    commands = env["commands"]["commands"]
    assert "MUSICPLAYER__-__KEY_SHIFT__+__KEY_U" in commands
    assert "MUSICPLAYER__-__KEY_SHIFT__+__KEY_X" in commands
    assert (
        env["bindings"][str([1, sorted(["KEY_SCRIPT", "KEY_SHIFT", "KEY_U"])])]
        == "MUSICPLAYER__-__KEY_SHIFT__+__KEY_U"
    )
    assert (
        env["bindings"][str([1, sorted(["KEY_SCRIPT", "KEY_SHIFT", "KEY_X"])])]
        == "MUSICPLAYER__-__KEY_SHIFT__+__KEY_X"
    )


@pytest.mark.unit
def test_sound_theme_resolution_prefers_local_soundpacks(tmp_path):
    manager = SettingsManager()
    local_root = tmp_path / "local" / "fenrir"
    system_root = tmp_path / "system" / "sounds" / "fenrir"
    local_theme = local_root / "sounds" / "default"
    system_theme = system_root / "default"
    local_theme.mkdir(parents=True)
    system_theme.mkdir(parents=True)
    (local_theme / "soundicons.conf").write_text(
        "Accept=Accept.wav\n", encoding="utf-8"
    )
    (system_theme / "soundicons.conf").write_text(
        "Accept=SystemAccept.wav\n", encoding="utf-8"
    )
    manager.user_resource_root = str(local_root)
    manager.system_sound_roots = [str(system_root)]

    assert manager.resolve_sound_theme_path("default") == str(local_theme)


@pytest.mark.unit
def test_sound_theme_resolution_accepts_absolute_theme_path(tmp_path):
    manager = SettingsManager()
    theme_path = tmp_path / "custom"
    theme_path.mkdir()
    (theme_path / "soundicons.conf").write_text(
        "Accept=Accept.wav\n", encoding="utf-8"
    )

    assert manager.resolve_sound_theme_path(str(theme_path)) == str(theme_path)
