from __future__ import annotations

import json
from pathlib import Path
from unittest.mock import MagicMock

import pytest
from pygit2 import Repository, Signature
from unicurses import KEY_BACKSPACE, KEY_DOWN, KEY_ENTER, KEY_RESIZE, KEY_UP

from pygittools.tui.pages.branches import BranchPickerPage, branch_picker_page
from pygittools.tui.pages.help import HelpPage, help_page
from pygittools.tui.pages.home import home_page
from pygittools.tui.pages.no_repo import NoRepoPage
from pygittools.tui.pages.projects import ProjectsPage, projects_page
from pygittools.tui.types import PageAction, PageContext


def test_home_page_on_enter_and_quit(page_ctx: PageContext) -> None:
	page = home_page()
	page.on_enter(page_ctx)
	assert page.status_text()
	result = page.handle_key(ord("q"))
	assert result.action == PageAction.QUIT


def test_home_page_draw_and_tabs(committed_repo: Repository) -> None:
	ctx = PageContext(repo=committed_repo, repo_path=Path(committed_repo.path))
	page = home_page()
	page.on_enter(ctx)
	page.draw(0, 20, 80)
	page.set_active_tab("log")
	page.draw(0, 20, 80)
	page.set_header_focus("repo")
	page.draw(0, 20, 80)
	page.handle_key(KEY_RESIZE)


def test_home_page_switch_to_input(page_ctx: PageContext) -> None:
	page = home_page()
	page.on_enter(page_ctx)
	page.handle_key(ord("a"))
	assert "Esc" in page.status_text()


def test_home_page_push_help(page_ctx: PageContext) -> None:
	page = home_page()
	page.on_enter(page_ctx)
	result = page.handle_key(ord("?"))
	assert result.action == PageAction.PUSH
	assert isinstance(result.next_page, HelpPage)


def test_home_page_draw_without_context() -> None:
	page = home_page()
	page.draw(0, 10, 80)


def test_no_repo_page(tmp_path: Path) -> None:
	page = NoRepoPage(tmp_path)
	page.on_enter(PageContext(repo=MagicMock(), repo_path=tmp_path))  # type: ignore[arg-type]
	page.draw(0, 10, 80)
	assert page.handle_key(ord("q")).action == PageAction.QUIT
	assert page.handle_key(ord("h")).action == PageAction.PUSH
	page.handle_key(KEY_RESIZE)


def test_help_page_scroll_and_pop() -> None:
	page = help_page()
	page.on_enter(PageContext(repo=MagicMock(), repo_path=Path(".")))  # type: ignore[arg-type]
	page.draw(0, 5, 80)
	page.handle_key(KEY_DOWN)
	page.handle_key(KEY_UP)
	assert page.handle_key(ord("q")).action == PageAction.POP
	page.handle_key(KEY_RESIZE)


def test_branch_picker_lists_and_filters(committed_repo: Repository) -> None:
	ctx = PageContext(repo=committed_repo, repo_path=Path(committed_repo.path))
	page = branch_picker_page()
	page.on_enter(ctx)
	page.draw(0, 10, 80)
	page.handle_key(ord("f"))
	page.handle_key(KEY_BACKSPACE)
	page.handle_key(KEY_DOWN)
	page.handle_key(KEY_UP)
	page.handle_key(KEY_ENTER)
	assert page.handle_key(ord("q")).action == PageAction.POP


def test_branch_picker_checkout_branch(committed_repo: Repository) -> None:
	commit = committed_repo.get(committed_repo.head.target)
	committed_repo.branches.create("feature", commit)
	ctx = PageContext(repo=committed_repo, repo_path=Path(committed_repo.path))
	page = branch_picker_page()
	page.on_enter(ctx)
	page.handle_key(KEY_DOWN)
	page.handle_key(KEY_ENTER)
	assert page.handle_key(KEY_ENTER).action == PageAction.POP


def test_branch_picker_create_branch(committed_repo: Repository) -> None:
	ctx = PageContext(repo=committed_repo, repo_path=Path(committed_repo.path))
	page = branch_picker_page()
	page.on_enter(ctx)
	page.handle_key(ord("n"))
	page.handle_key(ord("e"))
	page.handle_key(ord("w"))
	page.handle_key(KEY_ENTER)
	assert "new" in committed_repo.branches.local


def test_branch_picker_create_invalid_shows_error(committed_repo: Repository) -> None:
	ctx = PageContext(repo=committed_repo, repo_path=Path(committed_repo.path))
	page = branch_picker_page()
	page.on_enter(ctx)
	page.handle_key(ord(" "))
	page.handle_key(KEY_ENTER)
	assert page.status_text()


def test_branch_picker_draw_zero_height() -> None:
	page = BranchPickerPage()
	page.draw(0, 0, 80)


def test_projects_page_lists_repos(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
	root = tmp_path / "root"
	project = root / "demo"
	project.mkdir(parents=True)
	from pygit2 import init_repository

	repo = init_repository(str(project), bare=False)
	workdir = Path(repo.workdir)
	(workdir / "README").write_text("x\n", encoding="utf-8")
	repo.index.add("README")
	repo.index.write()
	tree = repo.index.write_tree()
	sig = Signature("t", "t@example.com")
	repo.create_commit("HEAD", sig, sig, "init", tree, [])
	settings = tmp_path / "settings.json"
	settings.write_text(json.dumps({"PROJECTROOT": str(root)}), encoding="utf-8")
	monkeypatch.setenv("PYGITWEB_SETTINGS_CONFIG", str(settings))
	ctx = PageContext(repo=Repository(str(project / ".git")), repo_path=project / ".git")
	page = projects_page()
	page.on_enter(ctx)
	page.draw(0, 10, 80)
	page.handle_key(KEY_DOWN)
	result = page.handle_key(KEY_ENTER)
	assert result.switch_repo == project.resolve()


def test_projects_page_empty(monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> None:
	settings = tmp_path / "settings.json"
	settings.write_text(json.dumps({"PROJECTROOT": str(tmp_path / "empty")}), encoding="utf-8")
	monkeypatch.setenv("PYGITWEB_SETTINGS_CONFIG", str(settings))
	page = projects_page()
	page.on_enter(PageContext(repo=MagicMock(), repo_path=tmp_path))  # type: ignore[arg-type]
	assert "No projects" in page.status_text()
	page.handle_key(KEY_ENTER)


def test_projects_page_draw_zero_height() -> None:
	ProjectsPage().draw(0, 0, 80)