from __future__ import annotations

from pathlib import Path

import pytest
from pygit2 import init_repository

from pygittools.tui.projects import (
	_branch_for_worktree,
	_export_ok,
	_find_projects_in_dir,
	_projects_from_file,
	list_projects,
)
from pygittools.tui.pygitweb_layout import PygitwebLayout


def _layout(tmp_path: Path, **overrides: object) -> PygitwebLayout:
	root = tmp_path / "root"
	root.mkdir()
	defaults = {
		"projectroot": root,
		"projects_list": root,
		"project_maxdepth": 2,
		"list_all": True,
		"export_ok": "",
	}
	defaults.update(overrides)
	return PygitwebLayout(**defaults)  # type: ignore[arg-type]


def _init_repo_with_commit(path: Path) -> None:
	from pygit2 import Signature, init_repository

	repo = init_repository(str(path), 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, [])


def test_list_projects_from_directory(tmp_path: Path) -> None:
	layout = _layout(tmp_path)
	project = layout.projectroot / "alpha"
	project.mkdir()
	_init_repo_with_commit(project)
	entries = list_projects(layout)
	assert len(entries) == 1
	assert entries[0].path == "alpha"
	assert entries[0].branch in {"main", "master"}


def test_list_projects_from_file(tmp_path: Path) -> None:
	layout = _layout(tmp_path)
	project = layout.projectroot / "beta"
	project.mkdir()
	_init_repo_with_commit(project)
	projects_file = tmp_path / "projects.txt"
	projects_file.write_text("beta\n", encoding="utf-8")
	layout = PygitwebLayout(
		projectroot=layout.projectroot,
		projects_list=projects_file,
		project_maxdepth=1,
		list_all=True,
		export_ok="",
	)
	entries = list_projects(layout)
	assert [entry.path for entry in entries] == ["beta"]


def test_list_projects_respects_export_ok(tmp_path: Path) -> None:
	layout = _layout(tmp_path, list_all=False, export_ok="git-daemon-export-ok")
	project = layout.projectroot / "hidden"
	project.mkdir()
	_init_repo_with_commit(project)
	assert list_projects(layout) == []
	(project / "git-daemon-export-ok").write_text("", encoding="utf-8")
	assert len(list_projects(layout)) == 1


def test_list_projects_missing_projects_list(tmp_path: Path) -> None:
	layout = PygitwebLayout(
		projectroot=tmp_path / "root",
		projects_list=tmp_path / "missing",
		project_maxdepth=1,
		list_all=True,
		export_ok="",
	)
	assert list_projects(layout) == []


def test_projects_from_file_skips_invalid_lines(tmp_path: Path) -> None:
	layout = _layout(tmp_path)
	projects_file = tmp_path / "projects.txt"
	projects_file.write_text("\n  \nmissing\n%20encoded\n", encoding="utf-8")
	assert (
		_projects_from_file(
			PygitwebLayout(
				projectroot=layout.projectroot,
				projects_list=projects_file,
				project_maxdepth=1,
				list_all=True,
				export_ok="",
			),
		)
		== []
	)


def test_find_projects_respects_maxdepth(tmp_path: Path) -> None:
	layout = _layout(tmp_path, project_maxdepth=1)
	deep = layout.projectroot / "a" / "b"
	deep.mkdir(parents=True)
	init_repository(str(deep), bare=False)
	assert _find_projects_in_dir(layout) == []


def test_export_ok_requires_repository(tmp_path: Path) -> None:
	path = tmp_path / "not-a-repo"
	path.mkdir()
	assert _export_ok(path, "") is False


def test_projects_from_file_read_error(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
	layout = _layout(tmp_path)
	projects_file = tmp_path / "projects.txt"
	projects_file.write_text("alpha\n", encoding="utf-8")

	def fail_read_text(self: Path, encoding: str = "utf-8") -> str:
		raise OSError("nope")

	monkeypatch.setattr(Path, "read_text", fail_read_text)
	assert (
		_projects_from_file(
			PygitwebLayout(
				projectroot=layout.projectroot,
				projects_list=projects_file,
				project_maxdepth=1,
				list_all=True,
				export_ok="",
			),
		)
		== []
	)


def test_find_projects_skips_inaccessible_dir(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
	layout = _layout(tmp_path)
	project = layout.projectroot / "secret"
	project.mkdir()
	_init_repo_with_commit(project)
	monkeypatch.setattr("pygittools.tui.projects.os.access", lambda _path, _mode: False)
	assert _find_projects_in_dir(layout) == []


def test_branch_for_invalid_worktree(tmp_path: Path) -> None:
	bad = tmp_path / "bad"
	bad.mkdir()
	assert _branch_for_worktree(bad) == "?"