"""Discover PyGitWeb projects (git repositories under PROJECTROOT)."""

from __future__ import annotations

import os
from dataclasses import dataclass
from pathlib import Path
from urllib.parse import unquote

from pygit2 import GitError, Repository, discover_repository

from pygittools.tui.branches import current_branch_name
from pygittools.tui.pygitweb_layout import PygitwebLayout


@dataclass(frozen=True, slots=True)
class ProjectEntry:
	path: str
	worktree: Path
	branch: str


def list_projects(layout: PygitwebLayout) -> list[ProjectEntry]:
	projects_list = layout.projects_list
	if projects_list.is_dir():
		raw = _find_projects_in_dir(layout)
	elif projects_list.is_file():
		raw = _projects_from_file(layout)
	else:
		raw = []
	entries: list[ProjectEntry] = []
	for project_path, worktree in raw:
		entries.append(
			ProjectEntry(
				path=project_path,
				worktree=worktree,
				branch=_branch_for_worktree(worktree),
			),
		)
	return sorted(entries, key=lambda entry: entry.path.casefold())


def _branch_for_worktree(worktree: Path) -> str:
	try:
		repo = Repository(str(worktree))
	except GitError:
		return "?"
	return current_branch_name(repo)


def _find_projects_in_dir(layout: PygitwebLayout) -> list[tuple[str, Path]]:
	root = layout.projects_list.resolve()
	projectroot = layout.projectroot.resolve()
	result: list[tuple[str, Path]] = []
	for dirpath, dirnames, _ in os.walk(root, topdown=True):
		rel = os.path.relpath(dirpath, root)
		depth = 0 if rel == "." else rel.count(os.sep) + 1
		if depth >= layout.project_maxdepth:
			dirnames.clear()
			continue
		for name in list(dirnames):
			path = Path(dirpath) / name
			if not path.is_dir():
				continue
			try:
				if not os.access(path, os.X_OK):
					continue
			except OSError:
				continue
			discovered = discover_repository(str(path))
			if discovered is None:
				continue
			project_path = os.path.relpath(path, projectroot).replace("\\", "/")
			if not layout.list_all and not _export_ok(path, layout.export_ok):
				continue
			worktree = path.resolve()
			result.append((project_path, worktree))
			dirnames.remove(name)
	return result


def _projects_from_file(layout: PygitwebLayout) -> list[tuple[str, Path]]:
	projectroot = layout.projectroot.resolve()
	result: list[tuple[str, Path]] = []
	try:
		lines = layout.projects_list.read_text(encoding="utf-8").splitlines()
	except OSError:
		return result
	for line in lines:
		line = line.strip()
		if not line:
			continue
		parts = line.split(None, 1)
		project_path = unquote(parts[0]) if parts else ""
		if not project_path:
			continue
		worktree = (projectroot / project_path).resolve()
		if not worktree.is_dir():
			continue
		if discover_repository(str(worktree)) is None:
			continue
		if not layout.list_all and not _export_ok(worktree, layout.export_ok):
			continue
		result.append((project_path, worktree))
	return result


def _export_ok(worktree: Path, export_ok: str) -> bool:
	if export_ok and not (worktree / export_ok).is_file():
		return False
	return discover_repository(str(worktree)) is not None