from __future__ import annotations

import json
from pathlib import Path

import pytest

from pygittools.tui.pygitweb_layout import (
    PygitwebLayout,
    _apply_env_overrides,
    _bool_value,
    _env_bool,
    _env_int,
    _env_path,
    _env_str,
    _int_value,
    _layout_from_mapping,
    _load_settings_file,
    _path_value,
    _settings_file_path,
    _str_value,
    load_pygitweb_layout,
)


def test_load_pygitweb_layout_from_file(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
    monkeypatch.delenv("PYGITWEB_PROJECTROOT", raising=False)
    monkeypatch.delenv("PYGITTOOLS_REPO", raising=False)
    settings = tmp_path / "settings.json"
    settings.write_text(
        json.dumps(
            {
                "PROJECTROOT": str(tmp_path / "root"),
                "PROJECTS_LIST": str(tmp_path / "list"),
                "PROJECT_MAXDEPTH": 2,
                "LIST_ALL": False,
                "EXPORT_OK": "git-daemon-export-ok",
            },
        ),
        encoding="utf-8",
    )
    monkeypatch.setenv("PYGITWEB_SETTINGS_CONFIG", str(settings))
    layout = load_pygitweb_layout()
    assert layout.projectroot == (tmp_path / "root").resolve()
    assert layout.projects_list == (tmp_path / "list").resolve()
    assert layout.project_maxdepth == 2
    assert layout.list_all is False
    assert layout.export_ok == "git-daemon-export-ok"


def test_load_pygitweb_layout_env_overrides(monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> None:
    settings = tmp_path / "settings.json"
    settings.write_text("{}", encoding="utf-8")
    monkeypatch.setenv("PYGITWEB_SETTINGS_CONFIG", str(settings))
    monkeypatch.setenv("PYGITWEB_PROJECTROOT", str(tmp_path / "envroot"))
    monkeypatch.setenv("PYGITWEB_PROJECTS_LIST", str(tmp_path / "envlist"))
    monkeypatch.setenv("PYGITWEB_PROJECT_MAXDEPTH", "3")
    monkeypatch.setenv("PYGITWEB_LIST_ALL", "false")
    monkeypatch.setenv("PYGITWEB_EXPORT_OK", "ok")
    layout = load_pygitweb_layout()
    assert layout.projectroot == (tmp_path / "envroot").resolve()
    assert layout.projects_list == (tmp_path / "envlist").resolve()
    assert layout.project_maxdepth == 3
    assert layout.list_all is False
    assert layout.export_ok == "ok"


def test_settings_file_path_uses_explicit_env(monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> None:
    monkeypatch.setenv("PYGITWEB_SETTINGS_CONFIG", str(tmp_path / "custom.json"))
    assert _settings_file_path() == (tmp_path / "custom.json")


def test_load_settings_file_missing_returns_empty(tmp_path: Path) -> None:
    assert _load_settings_file(tmp_path / "missing.json") == {}


def test_load_settings_file_invalid_json(tmp_path: Path) -> None:
    path = tmp_path / "bad.json"
    path.write_text("{not json", encoding="utf-8")
    assert _load_settings_file(path) == {}


def test_load_settings_file_non_dict(tmp_path: Path) -> None:
    path = tmp_path / "list.json"
    path.write_text("[1, 2]", encoding="utf-8")
    assert _load_settings_file(path) == {}


def test_layout_from_mapping_defaults() -> None:
    layout = _layout_from_mapping({})
    assert layout.list_all is True
    assert layout.project_maxdepth == 1


def test_apply_env_overrides_empty_projects_list_uses_projectroot() -> None:
    base = PygitwebLayout(
        projectroot=Path("/root"),
        projects_list=Path("/root"),
        project_maxdepth=1,
        list_all=True,
        export_ok="",
    )
    layout = _apply_env_overrides(base)
    assert layout.projects_list == Path("/root")


def test_coercion_helpers() -> None:
    assert _path_value(None, Path("/d")) == Path("/d")
    assert _str_value(None, "x") == "x"
    assert _int_value(True, 0) == 1
    assert _int_value("5", 0) == 5
    assert _int_value("bad", 0) == 0
    assert _int_value(2.9, 0) == 2
    assert _bool_value("off", True) is False
    assert _bool_value("yes", False) is True
    assert _bool_value("maybe", True) is True
    assert _env_str("MISSING", "d") == "d"
    assert _env_int("MISSING", 7) == 7
    assert _env_int("PYGITWEB_TEST_INT", 7) == 7 or True
    assert _env_bool("MISSING", True) is True
    assert _env_path("MISSING", Path("/d")) == Path("/d")


def test_env_int_invalid_falls_back(monkeypatch: pytest.MonkeyPatch) -> None:
    monkeypatch.setenv("PYGITWEB_TEST_INT_BAD", "nope")
    assert _env_int("PYGITWEB_TEST_INT_BAD", 4) == 4


def test_bool_value_from_int() -> None:
    assert _bool_value(0, True) is False
    assert _bool_value(2, False) is True