"""Filterable local branch picker."""

from __future__ import annotations

from unicurses import (  # type: ignore[import-untyped]
	A_BOLD,
	A_REVERSE,
	KEY_BACKSPACE,
	KEY_DOWN,
	KEY_ENTER,
	KEY_RESIZE,
	KEY_UP,
)

from pygittools.tui.branches import (
	checkout_branch,
	create_branch_from_current,
	current_branch_name,
	list_local_branches,
)
from pygittools.tui.draw import draw_line
from pygittools.tui.types import PageAction, PageContext, PageResult

_FILTER_PREFIX = "Filter: "


class BranchPickerPage:
	title = "branches"

	def __init__(self) -> None:
		self._ctx: PageContext | None = None
		self._filter = ""
		self._branches: list[str] = []
		self._filtered: list[str] = []
		self._cursor = 0
		self._scroll_offset = 0
		self._error: str | None = None

	def on_enter(self, ctx: PageContext) -> None:
		self._ctx = ctx
		self._filter = ""
		self._error = None
		self._cursor = 0
		self._scroll_offset = 0
		self._reload_branches()

	def status_text(self) -> str:
		if self._error:
			return self._error
		if not self._filtered:
			if self._filter.strip():
				return "Enter create branch — type name — Esc back"
			return "No matching branches — type to filter, Esc back"
		return "Enter checkout — type to filter — j/k move — Esc back"

	def draw(self, stdscr: int, height: int, width: int) -> None:
		del stdscr
		if height <= 0:
			return
		current = current_branch_name(self._ctx.repo) if self._ctx is not None else ""
		draw_line(0, 0, "Switch branch", width, A_BOLD)
		if height > 1:
			draw_line(1, 0, self._filter_label(width), width, A_REVERSE if self._cursor == 0 else 0)
		list_top = 2
		list_height = height - list_top
		if list_height <= 0:
			return
		self._ensure_cursor_visible(list_top, list_height)
		for view_row in range(list_height):
			index = self._scroll_offset + view_row
			if index >= len(self._filtered):
				break
			branch = self._filtered[index]
			marker = "* " if branch == current else "  "
			row_index = index + 1
			attr = A_REVERSE if self._cursor == row_index else 0
			draw_line(list_top + view_row, 0, f"{marker}{branch}", width, attr)

	def handle_key(self, key: int) -> PageResult:
		if key in (ord("q"), ord("Q"), 27):
			return PageResult(action=PageAction.POP)
		if key == KEY_RESIZE:
			return PageResult()
		if self._error is not None:
			self._error = None

		ctx = self._ctx
		if ctx is None:
			return PageResult()

		max_cursor = max(0, len(self._filtered))
		if key in (KEY_UP, ord("k"), ord("K")):
			self._cursor = max(0, self._cursor - 1)
			return PageResult()
		if key in (KEY_DOWN, ord("j"), ord("J")):
			self._cursor = min(max_cursor, self._cursor + 1)
			return PageResult()

		if self._cursor == 0:
			if key in (KEY_BACKSPACE, 127, 8):
				self._filter = self._filter[:-1]
				self._apply_filter()
				return PageResult()
			if 32 <= key <= 126:
				self._filter += chr(key)
				self._apply_filter()
				return PageResult()
			if key in (KEY_ENTER, 10, 13):
				if not self._filtered:
					return self._try_create_branch(ctx)
				self._cursor = 1
				return PageResult()

		if key in (KEY_ENTER, 10, 13) and self._cursor > 0:
			branch = self._filtered[self._cursor - 1]
			ok, error = checkout_branch(ctx.repo, branch)
			if ok:
				return PageResult(action=PageAction.POP)
			self._error = error
			return PageResult()

		return PageResult()

	def _try_create_branch(self, ctx: PageContext) -> PageResult:
		ok, error = create_branch_from_current(ctx.repo, self._filter)
		if ok:
			return PageResult(action=PageAction.POP)
		self._error = error
		return PageResult()

	def _reload_branches(self) -> None:
		if self._ctx is None:
			self._branches = []
			self._filtered = []
			return
		self._branches = list_local_branches(self._ctx.repo)
		self._apply_filter()

	def _apply_filter(self) -> None:
		needle = self._filter.casefold()
		if needle:
			self._filtered = [branch for branch in self._branches if needle in branch.casefold()]
		else:
			self._filtered = list(self._branches)
		max_cursor = max(0, len(self._filtered))
		self._cursor = min(self._cursor, max_cursor)

	def _filter_label(self, width: int) -> str:
		max_text = max(0, width - len(_FILTER_PREFIX) - 1)
		text = self._filter[-max_text:] if len(self._filter) > max_text else self._filter
		label = f"{_FILTER_PREFIX}{text}"
		if self._cursor == 0:
			label += "_"
		return label[:width]

	def _ensure_cursor_visible(self, list_top: int, list_height: int) -> None:
		del list_top
		if self._cursor <= 0:
			self._scroll_offset = 0
			return
		list_index = self._cursor - 1
		if list_index < self._scroll_offset:
			self._scroll_offset = list_index
		elif list_index >= self._scroll_offset + list_height:
			self._scroll_offset = list_index - list_height + 1


def branch_picker_page() -> BranchPickerPage:
	return BranchPickerPage()