import importlib.util
from pathlib import Path
from unittest.mock import Mock

import pytest


def _load_progress_module():
    module_path = (
        Path(__file__).resolve().parents[2]
        / "src"
        / "fenrirscreenreader"
        / "commands"
        / "onScreenUpdate"
        / "65000-progress_detector.py"
    )
    spec = importlib.util.spec_from_file_location(
        "fenrir_progress_detector", module_path
    )
    module = importlib.util.module_from_spec(spec)
    spec.loader.exec_module(module)
    return module


@pytest.mark.unit
def test_progress_detector_skips_typing_delta():
    progress_module = _load_progress_module()
    command = progress_module.command()
    command.env = {
        "commandBuffer": {"progress_monitoring": True},
        "runtime": {"DebugManager": Mock(write_debug_out=Mock())},
        "screen": {"new_delta": "x", "new_delta_is_typing": True},
    }
    command.is_current_line_prompt = Mock(return_value=False)
    command.is_real_progress_update = Mock(return_value=True)
    command.detect_progress = Mock()

    command.run()

    command.is_real_progress_update.assert_not_called()
    command.detect_progress.assert_not_called()


@pytest.mark.unit
def test_progress_detector_allows_long_tqdm_transfer_delta():
    progress_module = _load_progress_module()
    command = progress_module.command()
    sample = (
        "88%|"
        "████████████████████████████████████████████████████████████████"
        "████████████████████████████████████████████████████████████████"
        "████████████████████████████████████████████████████████████████"
        "█████████████████████████▊                                "
        "| 843M/954M [00:54<00:07, 15.2MB/s]"
    )
    command.env = {
        "commandBuffer": {"progress_monitoring": True},
        "runtime": {
            "DebugManager": Mock(write_debug_out=Mock()),
            "ScreenManager": Mock(is_screen_change=Mock(return_value=False)),
            "CursorManager": Mock(is_cursor_vertical_move=Mock(return_value=False)),
        },
        "screen": {
            "new_delta": sample,
            "new_content_text": sample,
            "old_cursor": {"x": 0, "y": 0},
            "new_cursor": {"x": 0, "y": 0},
        },
    }

    assert len(sample) > 200
    assert command.is_real_progress_update()


@pytest.mark.unit
def test_progress_detector_beeps_for_long_tqdm_transfer_delta():
    progress_module = _load_progress_module()
    command = progress_module.command()
    sample = (
        "90%|"
        "████████████████████████████████████████████████████████████████"
        "████████████████████████████████████████████████████████████████"
        "████████████████████████████████████████████████████████████████"
        "█████████████████████████████████████▍                            "
        "| 856M/954M [00:56<00:14, 6.78MB/s]"
    )
    command.env = {
        "commandBuffer": {
            "progress_monitoring": True,
            "lastProgressValue": -1,
            "lastProgressTime": 0,
        },
        "runtime": {
            "DebugManager": Mock(write_debug_out=Mock()),
            "ScreenManager": Mock(is_screen_change=Mock(return_value=False)),
            "CursorManager": Mock(is_cursor_vertical_move=Mock(return_value=False)),
        },
        "screen": {
            "new_delta": sample,
            "new_delta_is_typing": False,
            "new_content_text": sample,
            "old_cursor": {"x": 0, "y": 0},
            "new_cursor": {"x": 0, "y": 0},
        },
    }
    command.play_progress_tone = Mock()

    command.run()

    command.play_progress_tone.assert_called_once_with(90.0)
    assert command.env["commandBuffer"]["lastProgressValue"] == 90.0
