from __future__ import annotations

from pygitweb.static_tests.js_runtime import JsPage
from pygitweb.static_tests.pages import MANIFEST, board_shell, card_html, posted_json, requested


def _board(js: JsPage, html: str | None = None) -> None:
    js.set_html(
        html if html is not None else board_shell(cards_todo=card_html(ref="refs/tags/tasks/task_abcd", title="Ship"))
    )
    js.load("board-context.js")


def test_task_ids_drop_the_prefix_and_shorten(js: JsPage) -> None:
    _board(js, "<div></div>")
    assert js.call("board-context.js", "taskDisplayId", "") == ""
    assert js.call("board-context.js", "taskDisplayId", "refs/tags/tasks/task_abcd") == "abcd"
    assert js.call("board-context.js", "taskDisplayId", "refs/tags/tasks/custom") == "custom"
    assert js.call("board-context.js", "taskDisplayIdShort", "") == ""
    assert js.call("board-context.js", "taskDisplayIdShort", "ab") == "ab"
    assert js.call("board-context.js", "taskDisplayIdShort", "abcdef") == "cdef"


def test_context_comes_from_the_dataset_or_the_url(js: JsPage) -> None:
    _board(js)
    assert js.call("board-context.js", "getBoardContext") == {"project": "demo", "board": "Tasks"}
    js.set_html('<div class="board-columns"></div>')
    js.set_location("http://127.0.0.1/project/demo/board/?b=Sprint")
    js.load("board-context.js")
    assert js.call("board-context.js", "getBoardContext") == {"project": "demo", "board": "Sprint"}
    js.set_location("http://127.0.0.1/project/demo/board")
    assert js.call("board-context.js", "getBoardContext")["board"] == "Tasks"


def test_find_card_matches_the_task_ref(js: JsPage) -> None:
    _board(js)
    assert js.call("board-context.js", "findBoardCardByTaskRef", "") is None
    assert js.value("__loaded['board-context.js'].findBoardCardByTaskRef('missing')") is None
    assert js.value("__loaded['board-context.js'].findBoardCardByTaskRef('refs/tags/tasks/task_abcd') !== null") is True


def test_title_tooltip_uses_the_id_and_falls_back_to_untitled(js: JsPage) -> None:
    js.set_html('<div class="board-card"></div>')
    js.load("board-context.js")
    js.run("__loaded['board-context.js'].syncCardTitleLineTooltip(document.querySelector('.board-card'))")
    js.set_html(board_shell(cards_todo=card_html(title="  ")))
    js.run("__loaded['board-context.js'].syncCardTitleLineTooltip(document.querySelector('.board-card'))")
    assert js.attr(".board-card-title-line", "title") == "Untitled"
    js.set_html(board_shell(cards_todo=card_html(ref="refs/tags/tasks/task_abcd", title="Ship")))
    js.run(
        "__loaded['board-context.js'].setCardTaskRefDisplay("
        "document.querySelector('.board-card'), 'refs/tags/tasks/task_abcd', null)"
    )
    assert js.text(".board-card-task-id") == "abcd"
    assert js.text(".board-card-task-ref") == "refs/tags/tasks/task_abcd"
    assert js.attr(".board-card-title-line", "title") == "abcd: Ship"


def test_title_line_without_a_title_element_uses_untitled(js: JsPage) -> None:
    js.set_html(
        '<div class="board-card" data-task-ref="refs/tags/tasks/task_abcd">'
        '<div class="board-card-title-line"></div>'
        '<span class="board-card-task-id"></span>'
        '<div class="board-card-task-ref">old</div></div>'
    )
    js.load("board-context.js")
    js.run("__loaded['board-context.js'].syncCardTitleLineTooltip(document.querySelector('.board-card'))")
    assert js.attr(".board-card-title-line", "title") == "abcd: Untitled"
    js.run("__loaded['board-context.js'].setCardTaskRefDisplay(document.querySelector('.board-card'), '', 'abcd')")
    assert js.text(".board-card-task-ref") == ""


def test_error_hint_replaces_itself_and_expires(js: JsPage) -> None:
    _board(js, "<div></div>")
    js.call("board-context.js", "showBoardError", "nope")
    assert js.count(".board-task-error-hint") == 0
    _board(js)
    js.call("board-context.js", "showBoardError", "first")
    js.call("board-context.js", "showBoardError", "second")
    assert js.count(".board-task-error-hint") == 1
    assert js.text(".board-task-error-hint") == "second"
    js.tick()
    assert js.count(".board-task-error-hint") == 0


def test_column_badge_sums_points(js: JsPage) -> None:
    html = board_shell(
        cards_todo=card_html(ref="a", points="2") + card_html(ref="b", points="3") + card_html(ref="c", points=""),
    )
    _board(js, html)
    js.run("__loaded['board-context.js'].updateColumnBadge(null)")
    js.run("__loaded['board-context.js'].updateColumnBadge(document.querySelector('.board-column'))")
    assert js.text(".board-column-task-count") == "3"
    assert js.text(".board-column-points-total") == "5 pts"
    js.set_html('<div class="board-column"></div>')
    js.load("board-context.js")
    js.run("__loaded['board-context.js'].updateColumnBadge(document.querySelector('.board-column'))")
    assert js.count(".board-column-task-count") == 0


def test_field_update_posts_json_and_reports_failures(js: JsPage) -> None:
    _board(js, "<div></div>")
    assert js.settle("__loaded['board-context.js'].pushTaskFieldUpdate(null, {})") == {"ok": False, "status": 0}
    _board(js)
    card = "document.querySelector('.board-card')"
    js.route("tasks/update", error="offline")
    assert js.settle(f"__loaded['board-context.js'].pushTaskFieldUpdate({card}, {{a:1}})") == {
        "ok": False,
        "status": 0,
    }
    js.route("tasks/update", status=200)
    assert js.settle(f"__loaded['board-context.js'].pushTaskFieldUpdate({card}, {{title:'Ship'}})") == {
        "ok": True,
        "status": 200,
    }
    assert posted_json(js, "tasks/update")["title"] == "Ship"
    js.route("tasks/update", status=404)
    assert js.settle(f"__loaded['board-context.js'].pushTaskFieldUpdate({card}, {{}})")["status"] == 404
    js.route("tasks/update", error="offline")
    assert js.settle(f"__loaded['board-context.js'].pushTaskFieldUpdate({card}, {{}})") == {"ok": False, "status": 0}
    js.set_html('<div class="board-columns"><div class="board-card" data-task-ref="t"></div></div>')
    js.load("board-context.js")
    assert js.settle("__loaded['board-context.js'].pushTaskFieldUpdate(document.querySelector('.board-card'), {})") == {
        "ok": False,
        "status": 0,
    }


def test_refresh_stores_the_manifest_or_an_empty_one(js: JsPage) -> None:
    _board(js, '<div class="board-columns"></div>')
    js.set_location("http://127.0.0.1/")
    assert js.settle("__loaded['board-context.js'].refreshBoardRefManifest()") is None
    js.route("board-ref-manifest", body=MANIFEST)
    _board(js)
    got = js.settle("__loaded['board-context.js'].refreshBoardRefManifest()")
    assert got["commits"][0]["insert"] == "abcd"
    assert js.call("board-context.js", "getBoardRefManifest")["refs"][0]["insert"] == "main"
    js.route("board-ref-manifest", status=500)
    empty = js.settle("__loaded['board-context.js'].refreshBoardRefManifest()")
    assert empty == {"commits": [], "refs": []}
    js.route("board-ref-manifest", error="offline")
    assert js.settle("__loaded['board-context.js'].refreshBoardRefManifest()") == {"commits": [], "refs": []}
    assert requested(js, "board-ref-manifest") is True