"""Keyboard input modes for TUI pages (navigation vs text entry)."""

from __future__ import annotations

from dataclasses import dataclass
from typing import TYPE_CHECKING, Literal, Protocol

from pygittools.tui.changes_list import ChangesList
from pygittools.tui.log_list import CommitLogList
from pygittools.tui.pages.branches import branch_picker_page
from pygittools.tui.pages.help import help_page
from pygittools.tui.pages.projects import projects_page
from pygittools.tui.types import PageAction, PageContext, PageResult
from pygittools.tui.ucurses import (  # type: ignore[import-untyped]
	KEY_DOWN,
	KEY_ENTER,
	KEY_LEFT,
	KEY_RIGHT,
	KEY_UP,
)

if TYPE_CHECKING:
	from pygittools.tui.tasks_list import TasksBoardList

_KEY_ESC = 27
_HeaderFocus = Literal["changes", "repo", "branch"]
_HomeTab = Literal["status", "log", "tasks"]


@dataclass(frozen=True, slots=True)
class ContextDispatch:
	page_result: PageResult | None = None
	next_mode: Literal["nav", "input"] | None = None


class PageInputHost(Protocol):
	@property
	def header_focus(self) -> _HeaderFocus: ...

	def set_header_focus(self, focus: _HeaderFocus) -> None: ...

	@property
	def page_context(self) -> PageContext | None: ...

	@property
	def changes(self) -> ChangesList: ...

	@property
	def log(self) -> CommitLogList: ...

	@property
	def active_tab(self) -> _HomeTab: ...

	def set_active_tab(self, tab: _HomeTab) -> None: ...
	@property
	def tasks(self) -> TasksBoardList: ...


class NavContext:
	def status_hint(self, host: PageInputHost) -> str:
		if host.header_focus == "repo":
			return "Enter browse projects — j/k move — H/L switch tab"
		if host.header_focus == "branch":
			if host.active_tab == "tasks":
				return "Enter sync tasks — j/k move — H/L switch tab"
			return "Enter switch branch — j/k move — H/L switch tab"
		if host.active_tab == "log":
			return host.log.status_hint()
		if host.active_tab == "tasks":
			return host.tasks.status_hint()
		return host.changes.status_hint()

	def dispatch_key(self, host: PageInputHost, key: int) -> ContextDispatch:
		if _try_switch_tab(host, key):
			return ContextDispatch()

		if key == ord("?"):
			return ContextDispatch(page_result=PageResult(action=PageAction.PUSH, next_page=help_page()))

		if host.header_focus == "repo":
			if key in (KEY_DOWN, ord("j"), ord("J")):
				host.set_header_focus("branch")
			elif key in (KEY_ENTER, 10, 13):
				return ContextDispatch(page_result=PageResult(action=PageAction.PUSH, next_page=projects_page()))
			return ContextDispatch()

		if host.header_focus == "branch":
			if key in (KEY_UP, ord("k"), ord("K")):
				host.set_header_focus("repo")
			elif key in (KEY_DOWN, ord("j"), ord("J")):
				host.set_header_focus("changes")
			elif key in (KEY_ENTER, 10, 13):
				if host.active_tab == "tasks" and host.page_context is not None:
					host.tasks.sync_with_default_remote(host.page_context.repo)
					return ContextDispatch()
				return ContextDispatch(
					page_result=PageResult(action=PageAction.PUSH, next_page=branch_picker_page()),
				)
			return ContextDispatch()

		if key in (KEY_UP, ord("k"), ord("K")) and _content_list_is_at_top(host):
			host.set_header_focus("branch")
			return ContextDispatch()

		ctx = host.page_context
		if ctx is None:
			return ContextDispatch()
		if host.active_tab == "log":
			host.log.handle_nav_key(key, ctx.repo)
			return ContextDispatch()
		if host.active_tab == "tasks":
			page_result = host.tasks.handle_nav_key(key, ctx.repo)
			return ContextDispatch(page_result=page_result)
		nav_result = host.changes.handle_nav_key(key, ctx.repo)
		if nav_result.enter_input:
			return ContextDispatch(next_mode="input")
		return ContextDispatch()


class InputContext:
	def status_hint(self, host: PageInputHost) -> str:
		del host
		return "Esc relinquish input — Enter commit"

	def dispatch_key(self, host: PageInputHost, key: int) -> ContextDispatch:
		if key == _KEY_ESC:
			return ContextDispatch(next_mode="nav")
		ctx = host.page_context
		if ctx is not None:
			result = host.changes.handle_input_key(key, ctx.repo)
			if result.relinquish:
				return ContextDispatch(next_mode="nav")
		return ContextDispatch()


InputMode = NavContext | InputContext


def nav_context() -> NavContext:
	return NavContext()


def input_context() -> InputContext:
	return InputContext()


def _content_list_is_at_top(host: PageInputHost) -> bool:
	if host.active_tab == "log":
		return host.log.is_at_top()
	if host.active_tab == "tasks":
		return host.tasks.is_at_top()
	return host.changes.is_at_top()


def _try_switch_tab(host: PageInputHost, key: int) -> bool:
	tabs: tuple[_HomeTab, ...] = ("status", "log", "tasks")
	current = host.active_tab
	index = tabs.index(current)
	if key in (KEY_LEFT, ord("h"), ord("H")):
		if index > 0:
			host.set_active_tab(tabs[index - 1])
		return True
	if key in (KEY_RIGHT, ord("l"), ord("L")):
		if index < len(tabs) - 1:
			host.set_active_tab(tabs[index + 1])
		return True
	return False