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

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


@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 _export_filter(layout: PygitwebLayout) -> str:
    return "" if layout.list_all else layout.export_ok


def _find_projects_in_dir(layout: PygitwebLayout) -> list[tuple[str, Path]]:
    root = layout.projects_list.resolve()
    projectroot = layout.projectroot.resolve()
    export_ok = _export_filter(layout)
    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
            if not check_export_ok(str(path), export_ok):
                continue
            project_path = os.path.relpath(path, projectroot).replace("\\", "/")
            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()
    export_ok = _export_filter(layout)
    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 check_export_ok(str(worktree), export_ok):
            continue
        result.append((project_path, worktree))
    return result