from __future__ import annotations

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

_TASKS = [
    {
        "ref": "refs/tags/tasks/task_abcd",
        "id": "abcd",
        "title": "Ship",
        "description": "**bold**",
        "status": "TODO",
        "priority": "CRITICAL",
        "points": 2,
        "assignee": "Ada",
        "comments_count": 1,
        "due_date": "2020-01-02",
        "updated_at": "2020-01-03",
        "tags": "ui",
    },
    {
        "ref": "refs/tags/tasks/task_eeee",
        "title": "",
        "status": "IN_PROGRESS",
        "priority": "HIGH",
        "points": 1,
        "comments_count": 0,
    },
    {"ref": "refs/tags/tasks/task_ffff", "status": "DONE", "priority": "LOW", "points": 0},
    {"status": "TODO", "title": "Zero", "points": 0, "priority": "LOW"},
]


def test_preload_and_assign_icons(js: JsPage) -> None:
    js.set_html(board_shell(cards_todo=card_html(ref="t")))
    js.load("board-cards.js")
    js.call("board-cards.js", "preloadIcons")
    preloaded = js.value("__preloaded")
    assert len(preloaded) == 6
    assert any(src.endswith("cloud.svg") for src in preloaded)
    js.call("board-cards.js", "assignCloudIconToAllCards")
    assert js.attr(".board-card-icon", "data-icon") == "cloud"


def test_load_tasks_builds_cards_for_known_columns(js: JsPage) -> None:
    js.route("tasks/list", body=_TASKS)
    js.route("board-ref-manifest", body={"commits": [], "refs": []})
    js.set_html(board_shell())
    js.load("board-cards.js")
    js.settle("__loaded['board-cards.js'].loadTasksForBoard()")
    assert js.count('.board-column[data-status="TODO"] .board-card') == 2
    assert js.count('.board-column[data-status="IN_PROGRESS"] .board-card') == 1
    assert js.count('.board-column[data-status="DONE"] .board-card') == 0
    assert js.text(".board-card-title") == "Ship"
    assert "text-danger" in js.classes(".badge")
    assert js.text(".board-card-points-badge") == "2 pts"
    assert js.text(".board-card-assignee-compact") == "Ada"
    assert js.text(".board-card-comments-count-meta") == "1 comment"
    assert js.text(".board-card-due-date") == "2020-01-02"
    assert js.text(".board-card-points") == "2"
    assert js.text(".board-card-tags") == "ui"
    assert js.count(".board-card-description-full strong") == 1
    assert js.attr(".board-card-icon", "data-icon") == "cloud-filled"
    assert js.text(".board-column-task-count") == "2"
    assert js.text('.board-card[data-task-points="0"] .board-card-points-badge') == "0 pts"
    assert "text-secondary" in js.classes('.board-card[data-task-points="0"] .badge')
    assert js.text('.board-column[data-status="IN_PROGRESS"] .board-card-title') == "Untitled"
    assert js.text('.board-column[data-status="IN_PROGRESS"] .board-card-points-badge') == "1 pt"
    assert "text-warning" in js.classes('.board-column[data-status="IN_PROGRESS"] .badge')


def test_load_tasks_keeps_cards_when_the_response_is_unusable(js: JsPage) -> None:
    js.set_html('<div class="board-columns"></div>')
    js.set_location("http://127.0.0.1/")
    js.load("board-cards.js")
    js.settle("__loaded['board-cards.js'].loadTasksForBoard()")
    assert requested(js, "tasks/list") is False
    js.set_location("http://127.0.0.1/project/demo/board/")
    js.set_html(board_shell(cards_todo=card_html(ref="keep", title="Keep")))
    js.route("tasks/list", status=500)
    js.settle("__loaded['board-cards.js'].loadTasksForBoard()")
    assert js.text(".board-card-title") == "Keep"
    js.route("tasks/list", body={"nope": True})
    js.settle("__loaded['board-cards.js'].loadTasksForBoard()")
    assert js.text(".board-card-title") == "Keep"
    js.route("tasks/list", error="offline")
    js.settle("__loaded['board-cards.js'].loadTasksForBoard()")
    assert js.text(".board-card-title") == "Keep"


def test_load_tasks_without_a_template_clears_the_column(js: JsPage) -> None:
    js.route("tasks/list", body=[{"ref": "t", "title": "X", "status": "TODO"}])
    js.route("board-ref-manifest", body={"commits": [], "refs": []})
    js.set_html(board_shell(include_template=False, cards_todo=card_html(ref="old", title="Old")))
    js.load("board-cards.js")
    js.settle("__loaded['board-cards.js'].loadTasksForBoard()")
    assert js.count(".board-card") == 0


def test_fetch_and_reorder_follow_the_task_list(js: JsPage) -> None:
    js.set_html('<div class="board-columns"></div>')
    js.set_location("http://127.0.0.1/")
    js.load("board-cards.js")
    assert js.settle("__loaded['board-cards.js'].fetchBoardTasksJson()") is None
    js.set_html(
        board_shell(
            cards_todo=card_html(ref="a", title="A") + card_html(ref="b", title="B"),
            cards_progress=card_html(ref="c", title="C"),
        )
    )
    js.route("tasks/list", status=404)
    assert js.settle("__loaded['board-cards.js'].fetchBoardTasksJson()") is None
    js.route(
        "tasks/list",
        body=[{"ref": "b", "status": "TODO"}, {"ref": "a", "status": "TODO"}, {"ref": "c", "status": "IN_PROGRESS"}],
    )
    assert js.settle("__loaded['board-cards.js'].fetchBoardTasksJson()")[0]["ref"] == "b"
    js.run("__loaded['board-cards.js'].reorderBoardDomToTaskList(null)")
    js.run(
        "__loaded['board-cards.js'].reorderBoardDomToTaskList(["
        "{ref:'b', status:'TODO'}, {status:'TODO'}, {ref:'missing', status:'TODO'}, {ref:'a', status:'IN_PROGRESS'}"
        "])"
    )
    titles = js.texts('.board-column[data-status="TODO"] .board-card-title')
    assert titles == ["B"]
    progress = js.texts('.board-column[data-status="IN_PROGRESS"] .board-card-title')
    assert progress == ["C", "A"]


def test_add_card_posts_and_marks_success_or_failure(js: JsPage) -> None:
    js.route("tasks/create", body={"ref": "refs/tags/tasks/task_abcd"})
    js.set_html(board_shell())
    js.load("board-cards.js")
    js.call("board-cards.js", "bindAddCardButtons")
    js.click(".board-column-task-count")
    assert js.count(".board-card") == 0
    js.click(".board-column-add-card")
    assert js.text(".board-card-title") == "New task"
    assert js.attr(".board-card-icon", "data-icon") == "cloud-filled"
    assert js.text(".board-card-task-id") == "abcd"
    assert js.text(".board-column-task-count") == "1"
    body_url = next(str(item["url"]) for item in js.requests() if "tasks/create" in str(item["url"]))
    assert "title=New+task" in body_url or "title=New%20task" in body_url
    assert "status=TODO" in body_url
    js.route("tasks/create", status=500)
    js.click('.board-column[data-status="IN_PROGRESS"] .board-column-add-card')
    assert js.attr('.board-column[data-status="IN_PROGRESS"] .board-card-icon', "data-icon") == "cloud-exclamation"
    js.route("tasks/create", status=302)
    js.click(".board-column-add-card")
    pending = js.attrs('.board-column[data-status="TODO"] .board-card-icon', "data-icon")
    assert pending[-1] == "cloud-up"
    js.route("tasks/create", error="offline")
    js.click(".board-column-add-card")
    icons = js.attrs('.board-column[data-status="TODO"] .board-card-icon', "data-icon")
    assert icons[-1] == "cloud-exclamation"


def test_add_card_does_nothing_without_a_project_or_template(js: JsPage) -> None:
    js.set_html(board_shell(project="", include_template=True))
    js.set_location("http://127.0.0.1/")
    js.load("board-cards.js")
    js.call("board-cards.js", "bindAddCardButtons")
    js.click(".board-column-add-card")
    assert js.count(".board-card") == 0
    js.set_html(board_shell(include_template=False))
    js.call("board-cards.js", "bindAddCardButtons")
    js.click(".board-column-add-card")
    assert js.count(".board-card") == 0


def test_compact_assignee_edit_commits_or_restores(js: JsPage) -> None:
    js.route("tasks/list", body=[{"ref": "t1", "title": "Ship", "status": "TODO", "assignee": "Ada"}])
    js.route("board-ref-manifest", body={"commits": [], "refs": []})
    js.route("tasks/update", status=200)
    js.set_html(board_shell())
    js.load("board-cards.js")
    js.settle("__loaded['board-cards.js'].loadTasksForBoard()")
    js.click(".board-card-assignee-compact")
    assert js.count(".board-card-assignee-compact-edit") == 1
    js.dispatch(".board-card-assignee-compact-edit", "mousedown")
    js.set_prop(".board-card-assignee-compact-edit", "value", "Bea")
    js.dispatch(".board-card-assignee-compact-edit", "keydown", key="Enter")
    assert js.text(".board-card-assignee-compact") == "Bea"
    assert js.text(".board-card-assignee") == "Bea"
    assert posted_json(js, "tasks/update")["assignee"] == "Bea"
    assert js.prop(".board-card", "draggable") is True
    js.click(".board-card-assignee-compact")
    js.set_prop(".board-card-assignee-compact-edit", "value", "nope")
    js.dispatch(".board-card-assignee-compact-edit", "keydown", key="Escape")
    assert js.text(".board-card-assignee-compact") == "Bea"
    js.click(".board-card-assignee-compact")
    js.set_prop(".board-card-assignee-compact-edit", "value", "  ")
    js.dispatch(".board-card-assignee-compact-edit", "blur")
    assert js.text(".board-card-assignee-compact") == "None"
    assert posted_json(js, "tasks/update")["assignee"] is None