"""pgt TUI application loop."""

from __future__ import annotations

from pathlib import Path

from unicurses import (  # type: ignore[import-untyped]
	KEY_RESIZE,
	cbreak,
	clear,
	curs_set,
	endwin,
	getch,
	getmaxyx,
	initscr,
	keypad,
	noecho,
	refresh,
)

from pygittools.tui.pages.home import HomePage, home_page
from pygittools.tui.pages.no_repo import NoRepoPage
from pygittools.tui.repo import try_open_page_context
from pygittools.tui.status_bar import content_height, draw_status_bar, init_status_bar
from pygittools.tui.types import Page, PageAction, PageContext, PageResult


def run_tui(repo_path: Path | None = None) -> int:
	start = (repo_path or Path.cwd()).resolve()
	ctx = try_open_page_context(start)
	initial: Page = home_page() if ctx is not None else NoRepoPage(start)
	stack: list[Page] = [initial]

	stdscr = initscr()
	try:
		noecho()
		cbreak()
		curs_set(0)
		keypad(stdscr, True)
		status_attr = init_status_bar()

		if ctx is not None:
			stack[0].on_enter(ctx)

		while stack:
			page = stack[-1]
			height, width = getmaxyx(stdscr)
			clear()
			page.draw(stdscr, content_height(height), width)
			if height > 0:
				draw_status_bar(height - 1, width, page.status_text(), status_attr)
			refresh()

			try:
				key = getch()
			except KeyboardInterrupt:
				break
			if key == KEY_RESIZE:
				continue

			result = page.handle_key(key)
			ctx, stack = _apply_result(stack, ctx, result)
			if result.action == PageAction.QUIT:
				break
	except KeyboardInterrupt:
		pass
	finally:
		_persist_commit_draft(stack, ctx)
		endwin()

	return 0


def _persist_commit_draft(stack: list[Page], ctx: PageContext | None) -> None:
	if ctx is None:
		return
	for page in reversed(stack):
		if isinstance(page, HomePage):
			page.changes.persist_commit_draft(ctx.repo)
			return


def _apply_result(
	stack: list[Page],
	ctx: PageContext | None,
	result: PageResult,
) -> tuple[PageContext | None, list[Page]]:
	if result.switch_repo is not None:
		_persist_commit_draft(stack, ctx)
		new_ctx = try_open_page_context(result.switch_repo)
		if new_ctx is not None:
			ctx = new_ctx

	match result.action:
		case PageAction.REPLACE:
			if result.next_page is None:
				return ctx, stack
			if ctx is not None:
				result.next_page.on_enter(ctx)
			return ctx, [result.next_page]
		case PageAction.PUSH:
			if result.next_page is None:
				return ctx, stack
			if ctx is not None:
				result.next_page.on_enter(ctx)
			return ctx, [*stack, result.next_page]
		case PageAction.POP:
			if len(stack) <= 1:
				return ctx, stack
			stack = stack[:-1]
		case _:
			pass

	if result.switch_repo is not None and ctx is not None and stack:
		stack[-1].on_enter(ctx)

	return ctx, stack