from __future__ import annotations

from pathlib import Path

from ui_builder.manager import UIBuilderManager


def test_shortcut_sequences_are_normalized_and_persisted(tmp_path: Path) -> None:
    manager = UIBuilderManager(tmp_path, filename="ui.json")
    saved = manager.save({
        "version": 20,
        "project_name": "Hockey",
        "data_source": "hockey",
        "canvas": {"width": 1440, "height": 900},
        "tabs": [{"id": "main", "label": "Main"}],
        "components": [],
        "triggers": [{
            "id": "trigger-1",
            "name": "Start from event",
            "enabled": True,
            "source_action_id": "clock",
            "event": "click",
            "action": {"type": "run_sequence", "sequence_id": "start-clock"},
        }],
        "shortcut_sequences": [{
            "id": "start-clock",
            "name": "Старт времени",
            "description": "Запуск веба и vMix",
            "combo": "F1",
            "steps": [{
                "id": "sync",
                "type": "hockey_vmix_timers_start",
                "condition": "has_penalties",
                "game_timer_action_id": "hockey_game_timer",
                "hockey_timer_command": "toggle",
                "game_vmix_mode": "countdown",
                "game_vmix_input": "53",
                "game_vmix_selected_name": "CLOCK.Text",
                "penalty_display_mode": "soonest",
                "home_penalty_inputs": "54,55",
                "away_penalty_inputs": "56,57",
            }, {
                "id": "pause",
                "type": "delay",
                "milliseconds": "not-a-number",
            }],
        }],
    })

    assert saved["shortcut_sequences"][0]["combo"] == "F1"
    assert saved["shortcut_sequences"][0]["steps"][0]["type"] == "hockey_vmix_timers_start"
    assert saved["shortcut_sequences"][0]["steps"][0]["condition"] == "has_penalties"
    assert saved["shortcut_sequences"][0]["steps"][0]["hockey_timer_command"] == "toggle"
    assert saved["shortcut_sequences"][0]["steps"][0]["game_vmix_mode"] == "countdown"
    assert saved["shortcut_sequences"][0]["steps"][0]["game_vmix_selected_name"] == "CLOCK.Text"
    assert saved["shortcut_sequences"][0]["steps"][0]["penalty_display_mode"] == "soonest"
    assert saved["shortcut_sequences"][0]["steps"][1]["milliseconds"] == 0
    assert saved["triggers"][0]["action"]["sequence_id"] == "start-clock"


def test_shortcut_ui_contains_editor_reference_and_vmix_timer_sequence() -> None:
    app_js = Path("ui_builder/static/app.js").read_text(encoding="utf-8")
    index_html = Path("ui_builder/static/index.html").read_text(encoding="utf-8")

    assert "showShortcutsEditor" in app_js
    assert "showShortcutsReference" in app_js
    assert "hockey_vmix_timers_start" in app_js
    assert 'Function: "SetCountdown"' in app_js
    assert 'Function: "StartCountdown"' in app_js
    assert 'id="runtimeShortcutsBtn"' in index_html
    assert 'id="shortcutsBtn"' in index_html


def test_shortcut_vmix_editor_uses_searchable_inventory_controls() -> None:
    app_js = Path("ui_builder/static/app.js").read_text(encoding="utf-8")

    assert 'api("/vmix-inventory")' in app_js
    assert "vmixFunctionOptions" in app_js
    assert "vmixInputOptions" in app_js
    assert "vmixSelectedNameOptions" in app_js
    assert 'data-vmix-function-select' in app_js
    assert 'data-step-field="input"' in app_js
    assert 'data-step-field="selected_name"' in app_js
    assert "SetTextColour" in app_js
    assert "OverlayInput1In" in app_js


def test_shortcut_editor_collapses_existing_sequences_and_is_locked() -> None:
    app_js = Path("ui_builder/static/app.js").read_text(encoding="utf-8")

    assert "shortcutSequenceOpenId" in app_js
    assert "shortcut-sequence-compact" in app_js
    assert "data-sequence-edit" in app_js
    assert '{ locked: true, className: "modal-shortcuts-full" }' in app_js
    assert "Это окно защищено от случайного закрытия" in app_js


def test_shortcut_editor_layout_fixes_add_step_buttons_and_fullscreen_modal() -> None:
    css = Path("ui_builder/static/styles.css").read_text(encoding="utf-8")

    assert ".shortcut-add-steps .mini-btn" in css
    assert "width: auto;" in css
    assert ".modal-card.modal-shortcuts-full" in css
    assert "height: calc(100vh - 20px);" in css


def test_hockey_timer_shortcut_supports_native_countdown_and_legacy_text_mirror() -> None:
    app_js = Path("ui_builder/static/app.js").read_text(encoding="utf-8")
    assert 'Function: "StopCountdown"' in app_js
    assert 'Function: "SuspendCountdown"' not in app_js
    assert 'Function: "StopCountdown"' in app_js
    assert 'hockey_timer_command' in app_js
    assert 'game_vmix_mode' in app_js
    assert 'game_vmix_selected_name' in app_js
    assert 'vmixTimerMirrors' in app_js
    assert 'Function: "SetText"' in app_js
    assert 'combo: "Space"' in app_js


def test_global_shortcuts_capture_keys_before_focused_runtime_controls() -> None:
    app_js = Path("ui_builder/static/app.js").read_text(encoding="utf-8")

    assert 'window.addEventListener("keydown", (event) => {' in app_js
    assert '    }, true);\n\n    window.addEventListener("keyup"' in app_js
    assert 'event.stopImmediatePropagation()' in app_js
    assert 'function shortcutSequenceAllowed(sequence, event)' in app_js
    # Global shortcut sequences are intentionally independent of the active UI tab.
    sequence_allowed = app_js.split('function shortcutSequenceAllowed(sequence, event)', 1)[1].split('function currentHockeyPenaltyEntries()', 1)[0]
    assert 'isEffectivelyOnActiveTab' not in sequence_allowed
    assert 'isEditingTarget(event.target)' in sequence_allowed


def test_hockey_timer_targets_persist_selected_names_and_finish_actions(tmp_path: Path) -> None:
    manager = UIBuilderManager(tmp_path, filename="ui.json")
    saved = manager.save({
        "version": 20,
        "project_name": "Hockey",
        "data_source": "hockey",
        "canvas": {"width": 1440, "height": 900},
        "tabs": [{"id": "main", "label": "Main"}],
        "components": [],
        "triggers": [],
        "shortcut_sequences": [{
            "id": "timers",
            "name": "Timers",
            "combo": "Space",
            "steps": [{
                "id": "sync",
                "type": "hockey_vmix_timers_start",
                "game_vmix_input": "53",
                "game_vmix_selected_name": "CLOCK.Text",
                "home_penalty_targets": [
                    {"id": "home-1", "input": "54", "selected_name": "PENALTY1.Text"},
                    {"id": "home-2", "input": "55", "selected_name": "PENALTY2.Text"},
                ],
                "away_penalty_targets": [
                    {"id": "away-1", "input": "56", "selected_name": "PENALTY1.Text"},
                ],
                "timer_finish_actions": [{
                    "id": "finish-1",
                    "enabled": True,
                    "source": "game",
                    "input": "70",
                    "overlay": "3",
                    "duration_ms": 4500,
                }],
            }],
        }],
    })

    step = saved["shortcut_sequences"][0]["steps"][0]
    assert step["game_vmix_selected_name"] == "CLOCK.Text"
    assert step["penalty_display_mode"] == "soonest"
    assert step["home_penalty_targets"][0] == {
        "id": "home-1", "input": "54", "selected_name": "PENALTY1.Text",
        "overlay": "2", "auto_hide_on_finish": True,
    }
    assert step["away_penalty_targets"][0]["selected_name"] == "PENALTY1.Text"
    assert step["timer_finish_actions"][0]["source"] == "game"
    assert step["timer_finish_actions"][0]["overlay"] == "3"
    assert step["timer_finish_actions"][0]["duration_ms"] == 4500


def test_hockey_countdown_uses_selected_name_for_game_and_penalty_targets() -> None:
    app_js = Path("ui_builder/static/app.js").read_text(encoding="utf-8")

    assert 'function vmixCountdownSyncCommands(input, selectedName' in app_js
    assert 'SelectedName: String(selectedName || "").trim()' in app_js
    assert 'step.game_vmix_selected_name, () => gameTimerState.currentMs' in app_js
    assert 'target.input, target.selected_name, () => event.remainingMs' in app_js
    assert 'Input: target.input, SelectedName: target.selected_name' in app_js
    assert 'vmixTextSelectedNameOptions' in app_js
    assert 'data-penalty-target-field="selected_name"' in app_js
    assert 'data-finish-action-add' in app_js
    assert 'OverlayInput${overlay}In' in app_js
    assert 'OverlayInput${overlay}Out' in app_js


def test_overlay_group_repeat_uses_transition_out_not_all_off():
    js = Path("ui_builder/static/app.js").read_text(encoding="utf-8")
    assert 'Function: "OverlayInputAllOff"' not in js
    for layer in range(1, 5):
        assert f'Function: "OverlayInput{layer}Out"' in js


def test_build90_migrates_old_text_timer_transport_to_native_countdown(tmp_path: Path) -> None:
    manager = UIBuilderManager(tmp_path, filename="ui.json")
    saved = manager.save({
        "version": 21,
        "project_name": "Hockey",
        "data_source": "hockey",
        "canvas": {"width": 1440, "height": 900},
        "tabs": [{"id": "main", "label": "Main"}],
        "components": [],
        "triggers": [],
        "shortcut_sequences": [{
            "id": "timers", "name": "Timers", "combo": "Space",
            "steps": [{
                "id": "sync", "type": "hockey_vmix_timers_start",
                "game_vmix_mode": "text", "penalty_vmix_mode": "text",
            }],
        }],
    })
    step = saved["shortcut_sequences"][0]["steps"][0]
    assert saved["version"] == 22
    assert step["game_vmix_mode"] == "countdown"
    assert step["penalty_vmix_mode"] == "countdown"


def test_build90_keeps_explicit_legacy_text_mode_after_v22(tmp_path: Path) -> None:
    manager = UIBuilderManager(tmp_path, filename="ui.json")
    saved = manager.save({
        "version": 22,
        "project_name": "Hockey",
        "data_source": "hockey",
        "canvas": {"width": 1440, "height": 900},
        "tabs": [{"id": "main", "label": "Main"}],
        "components": [], "triggers": [],
        "shortcut_sequences": [{
            "id": "timers", "name": "Timers", "combo": "Space",
            "steps": [{
                "id": "sync", "type": "hockey_vmix_timers_start",
                "game_vmix_mode": "text", "penalty_vmix_mode": "text",
            }],
        }],
    })
    step = saved["shortcut_sequences"][0]["steps"][0]
    assert step["game_vmix_mode"] == "text"
    assert step["penalty_vmix_mode"] == "text"


def test_build90_native_countdown_avoids_per_second_transport() -> None:
    app_js = Path("ui_builder/static/app.js").read_text(encoding="utf-8")
    assert 'game_vmix_mode !== "countdown"' in app_js
    assert 'const countdownMode = step.penalty_vmix_mode === "countdown"' in app_js
    assert 'Function: "StopCountdown"' in app_js
    assert 'Function: "SuspendCountdown"' not in app_js
    assert 'Function: "StopCountdown"' in app_js
    assert 'signal: controller.signal' in app_js
    assert 'vmixCommandQueue: Promise.resolve()' in app_js
    # Per-second pushes are restricted to the legacy Text mirror map.
    assert 'eventName === "timer_tick" && state.vmixTimerMirrors.has(component.action_id)' in app_js
