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) == "?"