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