"""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