from __future__ import annotations

from pathlib import Path
from unittest.mock import MagicMock, patch

from pygit2 import Repository, init_repository

from pygittools.tui.app import _apply_result, _persist_commit_draft, run_tui
from pygittools.tui.pages.home import home_page
from pygittools.tui.pages.no_repo import NoRepoPage
from pygittools.tui.types import PageAction, PageContext, PageResult


def test_persist_commit_draft_skips_without_context() -> None:
	_persist_commit_draft([], None)


def test_persist_commit_draft_from_home_page(page_ctx: PageContext) -> None:
	page = home_page()
	page.on_enter(page_ctx)
	page.changes.set_commit_message("draft")
	_persist_commit_draft([page], page_ctx)
	from pygittools.tui.commit_draft import load_commit_draft

	assert load_commit_draft(page_ctx.repo_path, page_ctx.repo) == "draft"


def test_apply_result_replace(page_ctx: PageContext) -> None:
	next_page = home_page()
	stack = [NoRepoPage(Path("/tmp"))]
	ctx, new_stack = _apply_result(
		stack,
		page_ctx,
		PageResult(action=PageAction.REPLACE, next_page=next_page),
	)
	assert ctx is page_ctx
	assert new_stack == [next_page]


def test_apply_result_replace_without_page(page_ctx: PageContext) -> None:
	stack = [home_page()]
	ctx, new_stack = _apply_result(stack, page_ctx, PageResult(action=PageAction.REPLACE))
	assert new_stack is stack


def test_apply_result_push_and_pop(page_ctx: PageContext) -> None:
	home = home_page()
	home.on_enter(page_ctx)
	stack = [home]
	overlay = NoRepoPage(Path("/tmp"))
	ctx, stack = _apply_result(stack, page_ctx, PageResult(action=PageAction.PUSH, next_page=overlay))
	assert len(stack) == 2
	ctx, stack = _apply_result(stack, page_ctx, PageResult(action=PageAction.POP))
	assert len(stack) == 1


def test_apply_result_pop_keeps_root(page_ctx: PageContext) -> None:
	home = home_page()
	ctx, stack = _apply_result([home], page_ctx, PageResult(action=PageAction.POP))
	assert stack == [home]


def test_apply_result_switch_repo(page_ctx: PageContext, tmp_path: Path) -> None:
	repo_dir = tmp_path / "other"
	repo_dir.mkdir()
	init_repository(str(repo_dir), bare=False)
	home = home_page()
	home.on_enter(page_ctx)
	ctx, stack = _apply_result(
		[home],
		page_ctx,
		PageResult(action=PageAction.PUSH, switch_repo=repo_dir),
	)
	assert ctx is not None
	assert stack[-1] is home


def test_apply_result_switch_repo_reenters_page(page_ctx: PageContext, tmp_path: Path) -> None:
	repo_dir = tmp_path / "other"
	repo_dir.mkdir()
	init_repository(str(repo_dir), bare=False)
	home = home_page()
	home.on_enter(page_ctx)
	ctx, stack = _apply_result(
		[home],
		page_ctx,
		PageResult(action=PageAction.NONE, switch_repo=repo_dir),
	)
	assert ctx is not None
	assert stack[-1] is home


def _run_tui_once(repo_dir: Path, keys: list[int]) -> int:
	with patch("pygittools.tui.app.initscr") as initscr:
		initscr.return_value = MagicMock()
		with (
			patch("pygittools.tui.app.getmaxyx", return_value=(24, 80)),
			patch("pygittools.tui.app.getch", side_effect=keys),
			patch("pygittools.tui.app.noecho"),
			patch("pygittools.tui.app.cbreak"),
			patch("pygittools.tui.app.curs_set"),
			patch("pygittools.tui.app.keypad"),
			patch("pygittools.tui.app.clear"),
			patch("pygittools.tui.app.refresh"),
			patch("pygittools.tui.app.endwin"),
			patch("pygittools.tui.app.init_tui_color_theme"),
			patch("pygittools.tui.app.init_tab_colors"),
			patch("pygittools.tui.app.draw_status_bar"),
			patch("pygittools.tui.app.status_bar_attr", return_value=0),
		):
			return run_tui(repo_dir)


def test_run_tui_quits_on_q(committed_repo: Repository) -> None:
	assert _run_tui_once(Path(committed_repo.workdir), [ord("q")]) == 0


def test_run_tui_no_repo(tmp_path: Path) -> None:
	assert _run_tui_once(tmp_path, [ord("q")]) == 0