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 _open(js: JsPage, *, cards: str | None = None, project: str = "demo") -> None:
    js.route("board/list", body=[{"name": "Tasks"}, {"name": "Other"}])
    js.route("comments/list", body=[])
    js.route("board-ref-manifest", body=MANIFEST)
    js.route("tasks/list", body=[])
    js.route("tasks/update", status=200)
    html = board_shell(
        project=project,
        cards_todo=cards if cards is not None else card_html(ref="t1", title="Ship", description="see #abcd"),
    )
    js.set_html(html)
    js.load("board-popout.js")
    js.settle("__loaded['board-context.js'].refreshBoardRefManifest()")
    js.run("__loaded['board-popout.js'].showCardPopout(document.querySelector('.board-card'))")


def test_popout_edits_post_the_card_fields(js: JsPage) -> None:
    _open(js)
    assert "d-none" not in js.classes(".board-card-details")
    assert js.count(".board-card-popout-overlay") == 1
    assert js.count(".board-ref-commit") == 1
    js.click(".board-card-title")
    js.click(".board-card-title")
    js.set_prop(".board-card-title-edit", "value", "  ")
    js.dispatch(".board-card-title-edit", "keydown", key="Enter")
    assert js.text(".board-card-title") == "Untitled"
    js.click(".board-card-description-full")
    js.set_prop(".board-card-description-edit", "value", "updated")
    js.dispatch(".board-card-description-edit", "blur")
    assert js.text(".board-card-description-preview") == "updated"
    js.run("document.querySelector('.board-card-due-date').textContent = '2020-01-02 extra';")
    js.click(".board-card-due-date")
    assert js.prop(".board-card-due-date-edit", "value") == "2020-01-02"
    js.set_prop(".board-card-due-date-edit", "value", "")
    js.dispatch(".board-card-due-date-edit", "blur")
    assert js.text(".board-card-due-date") == "None"
    js.click(".board-card-status")
    js.run("document.querySelector('.board-card-status-edit option').textContent = 'In Progress';")
    js.dispatch(".board-card-status-edit", "change")
    assert js.text(".board-card-status") == "In Progress"
    assert js.attr(".board-card", "data-task-status") == "IN_PROGRESS"
    js.click(".board-card-priority")
    js.run("document.querySelector('.board-card-priority-edit option').textContent = 'High';")
    js.dispatch(".board-card-priority-edit", "change")
    assert js.text(".board-card-priority") == "High"
    js.click(".board-card-points")
    assert js.count(".board-card-points-edit option") == 9
    js.set_prop(".board-card-points-edit", "value", "5")
    js.dispatch(".board-card-points-edit", "change")
    assert js.text(".board-card-points") == "5"
    assert js.attr(".board-card", "data-task-points") == "5"
    js.click(".board-card-assignee")
    js.set_prop(".board-card-assignee-edit", "value", "Ada")
    js.dispatch(".board-card-assignee-edit", "keydown", key="Enter")
    assert js.text(".board-card-assignee-compact") == "Ada"
    js.run("document.querySelector('.board-card-tags').textContent = 'ui';")
    js.dispatch(".board-card-tags", "blur")
    body = posted_json(js, "tasks/update")
    assert body["title"] == "Untitled"
    assert body["description"] == "updated"
    assert body["status"] == "IN_PROGRESS"
    assert body["priority"] == "HIGH"
    assert body["points"] == 5
    assert body["assignee"] == "Ada"
    assert body["due_date"] is None
    assert body["tags"] == "ui"


def test_due_date_keeps_a_typed_value_and_rejects_junk(js: JsPage) -> None:
    _open(js)
    js.run("document.querySelector('.board-card-due-date').textContent = 'soon';")
    js.click(".board-card-due-date")
    assert js.prop(".board-card-due-date-edit", "value") == ""
    js.set_prop(".board-card-due-date-edit", "value", "2024-05-06")
    js.dispatch(".board-card-due-date-edit", "blur")
    assert posted_json(js, "tasks/update")["due_date"] == "2024-05-06"


def test_backdrop_restores_the_card_ahead_of_its_sibling(js: JsPage) -> None:
    _open(js, cards=card_html(ref="t1", title="A") + card_html(ref="t2", title="B"))
    assert js.count(".board-card-popout-overlay .board-card") == 1
    js.click(".board-card-popout-overlay")
    assert js.count(".board-card-popout-overlay") == 0
    titles = js.texts(".board-column-cards .board-card-title")
    assert titles == ["A", "B"]
    assert "d-none" in js.classes(".board-card-details")
    assert js.attr(".board-card", "draggable") == "true"


def test_escape_closes_the_popout(js: JsPage) -> None:
    _open(js, cards=card_html(ref="t1", title="A") + card_html(ref="t2", title="B"))
    js.click(".board-card-popout .board-card-title")
    js.set_prop(".board-card-title-edit", "value", "Renamed")
    js.dispatch(".board-card-title-edit", "keydown", key="Escape")
    assert js.count(".board-card-popout-overlay") == 0
    assert js.count(".board-card-title-edit") == 0
    assert js.texts(".board-column-cards .board-card-title") == ["Renamed", "B"]
    assert "d-none" in js.classes(".board-card-details")
    assert js.attr(".board-card", "draggable") == "true"
    js.dispatch("body", "keydown", key="Escape")
    assert js.count(".board-card") == 2


def test_escape_closes_suggestions_before_the_popout(js: JsPage) -> None:
    _open(js)
    js.click(".board-card-description-full")
    js.set_prop(".board-card-description-edit", "value", "@")
    js.set_prop(".board-card-description-edit", "selectionStart", 1)
    js.dispatch(".board-card-description-edit", "input")
    assert js.count(".board-ref-suggest:not(.d-none)") == 1
    js.dispatch(".board-card-description-edit", "keydown", key="Escape")
    assert js.count(".board-ref-suggest:not(.d-none)") == 0
    assert js.count(".board-card-popout-overlay") == 1
    js.dispatch(".board-card-description-edit", "keydown", key="Escape")
    assert js.count(".board-card-popout-overlay") == 0


def test_closing_the_last_card_appends_it(js: JsPage) -> None:
    _open(js, cards=card_html(ref="t1", title="Only"))
    js.click(".board-card-popout-overlay")
    assert js.text(".board-column-cards .board-card-title") == "Only"


def test_delete_and_archive_ask_before_removing_the_card(js: JsPage) -> None:
    js.route("tasks/delete", status=200)
    js.route("tasks/archive", status=200)
    _open(js)
    js.run("__confirmYes = false;")
    js.click(".board-card-delete-btn")
    assert requested(js, "tasks/delete") is False
    assert "permanently" in js.value("__confirms")[0]
    js.run("__confirmYes = true;")
    js.click(".board-card-delete-btn")
    assert js.count(".board-card") == 0
    _open(js)
    js.route("tasks/delete", status=500)
    js.click(".board-card-delete-btn")
    assert js.count(".board-card") == 1
    js.click(".board-card-archive-btn")
    assert js.count(".board-card") == 0
    assert "Archive this task" in js.value("__confirms")[-1]


def test_archive_failure_leaves_the_card(js: JsPage) -> None:
    js.route("tasks/archive", error="offline")
    _open(js)
    js.click(".board-card-archive-btn")
    assert js.count(".board-card") == 1


def test_move_removes_the_card_or_shows_an_error(js: JsPage) -> None:
    js.route("tasks/move", status=200)
    _open(js)
    labels = js.texts(".board-card-move-select option")
    assert "Tasks" not in labels
    assert "Other" in labels
    js.dispatch(".board-card-move-select", "change")
    assert requested(js, "tasks/move") is False
    js.set_prop(".board-card-move-select", "value", "Other")
    js.dispatch(".board-card-move-select", "change")
    assert js.count(".board-card-popout-overlay") == 0
    assert any("target=Other" in str(item["url"]) for item in js.requests())
    js.route("tasks/move", status=401)
    _open(js)
    js.set_prop(".board-card-move-select", "value", "Other")
    js.dispatch(".board-card-move-select", "change")
    assert "Not authorized" in js.text(".board-task-error-hint")
    assert js.prop(".board-card-move-select", "value") == ""
    js.route("tasks/move", status=500)
    js.set_prop(".board-card-move-select", "value", "Other")
    js.dispatch(".board-card-move-select", "change")
    assert "Could not move task" in js.text(".board-task-error-hint")
    js.route("tasks/move", error="offline")
    js.set_prop(".board-card-move-select", "value", "Other")
    js.dispatch(".board-card-move-select", "change")
    assert "Could not move task" in js.text(".board-task-error-hint")


def test_actions_without_a_ref_or_project_are_not_bound(js: JsPage) -> None:
    _open(js, cards=card_html(title="Draft"), project="")
    js.set_location("http://127.0.0.1/")
    js.click(".board-card-delete-btn")
    assert js.value("__confirms") == []
    assert requested(js, "tasks/delete") is False


def test_assignee_cleared_to_none_posts_null(js: JsPage) -> None:
    _open(js)
    js.run("document.querySelector('.board-card-assignee').textContent = 'Ada';")
    js.click(".board-card-assignee")
    js.set_prop(".board-card-assignee-edit", "value", "")
    js.dispatch(".board-card-assignee-edit", "blur")
    assert js.text(".board-card-assignee") == "None"
    assert posted_json(js, "tasks/update")["assignee"] is None