"""Чтение README.md и безопасное чтение ``app/docs/*.md`` для API документации.

Разметка Markdown преобразуется в браузере: ``/static/js/vendor/marked.min.js`` и
``purify.min.js`` (файлы входят в репозиторий, без CDN).

README: ``KIND_K8S_README_PATH`` или ``README.md`` в корне рядом с ``app/``;
в Docker-образе — ``/opt/kind-k8s/README.md``. Файлы под ``app/docs/`` — через
``resolve_app_docs_markdown`` / ``read_app_docs_file_text`` (эндпоинт ``GET /api/v1/docs/file``).

Автор: Сергей Антропов
Сайт: https://devops.org.ru
"""

from __future__ import annotations

import logging
import os
from pathlib import Path

logger = logging.getLogger("kind_k8s.readme_doc")

# app/core/readme_doc.py: parents[2] = корень репозитория (рядом с app/) или /opt/kind-k8s в образе
_LIB_FILE = Path(__file__).resolve()


def _candidates_without_env() -> list[Path]:
    """
    Возможные пути к README без KIND_K8S_README_PATH.

    Порядок: родитель каталога app/ (типично репозиторий), затем фиксированный путь образа.
    В compose рекомендуется монтировать ./README.md → /opt/kind-k8s/README.md (см. docker-compose.yml).
    """
    out: list[Path] = []
    seen: set[Path] = set()
    try:
        repo_readme = (_LIB_FILE.parents[2] / "README.md").resolve()
        if repo_readme not in seen:
            seen.add(repo_readme)
            out.append(repo_readme)
    except (IndexError, OSError):
        pass
    fixed = Path("/opt/kind-k8s/README.md")
    try:
        fixed_r = fixed.resolve()
        if fixed_r not in seen:
            seen.add(fixed_r)
            out.append(fixed_r)
    except OSError:
        out.append(fixed)
    return out


def get_readme_path() -> Path | None:
    """Первый существующий путь к README или ``None``."""
    raw = (os.environ.get("KIND_K8S_README_PATH") or "").strip()
    if raw:
        p = Path(raw).expanduser().resolve()
        return p if p.is_file() else None
    for p in _candidates_without_env():
        if p.is_file():
            return p
    return None


def read_readme_text() -> str:
    """Прочитать README как UTF-8; ``FileNotFoundError`` если файла нет."""
    raw = (os.environ.get("KIND_K8S_README_PATH") or "").strip()
    if raw:
        p = Path(raw).expanduser().resolve()
        if not p.is_file():
            logger.warning("KIND_K8S_README_PATH: файл не найден: %s", p)
            raise FileNotFoundError(str(p))
        text = p.read_text(encoding="utf-8")
        logger.debug("README из KIND_K8S_README_PATH, %s символов", len(text))
        return text

    for p in _candidates_without_env():
        if p.is_file():
            text = p.read_text(encoding="utf-8")
            logger.info("README прочитан: %s (%s символов)", p, len(text))
            return text

    logger.warning(
        "README.md не найден. Проверены пути: %s. "
        "В Docker Compose добавьте монтирование ./README.md:/opt/kind-k8s/README.md "
        "или пересоберите образ (COPY README.md в Dockerfile).",
        [str(x) for x in _candidates_without_env()],
    )
    raise FileNotFoundError("README.md")


def repo_root() -> Path:
    """Корень репозитория (родитель каталога ``app/``)."""
    return _LIB_FILE.parents[2]


def resolve_app_docs_markdown(relative_path: str) -> Path | None:
    """
    Безопасно разрешить путь к ``.md`` только внутри ``app/docs/``.

    Ожидается вид ``app/docs/api_routes.md`` (без ``..`` и абсолютных путей).
    """
    raw = (relative_path or "").strip().lstrip("/").replace("\\", "/")
    if not raw or ".." in raw or "\x00" in raw:
        return None
    if not raw.endswith(".md"):
        return None
    if not raw.startswith("app/docs/"):
        return None
    base = repo_root()
    try:
        full = (base / raw).resolve()
        allowed = (base / "app" / "docs").resolve()
        full.relative_to(allowed)
    except (ValueError, OSError):
        return None
    if not full.is_file():
        return None
    return full


def read_app_docs_file_text(relative_path: str) -> str:
    """Прочитать UTF-8 текст файла под ``app/docs/``; ``FileNotFoundError`` если путь недопустим или файла нет."""
    p = resolve_app_docs_markdown(relative_path)
    if p is None:
        raise FileNotFoundError(relative_path)
    text = p.read_text(encoding="utf-8")
    logger.debug("Документ app/docs: %s, %s символов", p, len(text))
    return text
