"""Application-file BFF adapter for Pages starters (Nuxt, React, HTML).

This is the generated-app port for file_id lifecycle. It is not storage.file.*
and does not expose R2/S3/ARTIFACTS locators.
"""
from __future__ import annotations

from pathlib import Path

from src.domain.codegen.local_backup import move_to_bak

_PAGES_TYPES = frozenset({"html", "react_app", "nuxt_app"})
ADAPTER_MARKER = "p2hs-files"

_LOCAL_FILE_ROUTES = (
    "functions/_lib/p2hs-files.mjs",
    "functions/api/files/[[path]].js",
    "functions/api/files.js",
    "server/utils/p2hs-files.mjs",
    "server/api/files/[...path].ts",
    "server/api/files/index.post.ts",
    "server/api/files.ts",
    "server/api/files/index.ts",
)


def file_adapter_files(project_type: str) -> dict[str, str]:
    if project_type not in _PAGES_TYPES:
        return {}
    root = Path(__file__).with_name("runtime")
    shared = (root / "p2hs-files.mjs").read_text(encoding="utf-8")
    files = {
        "functions/_lib/p2hs-files.mjs": shared,
        "functions/api/files.js": (root / "files-root-fn.js").read_text(
            encoding="utf-8"
        ),
        "functions/api/files/[[path]].js": (root / "files-pages-fn.js").read_text(
            encoding="utf-8"
        ),
    }
    if project_type == "nuxt_app":
        files["server/utils/p2hs-files.mjs"] = shared
        files["server/api/files/[...path].ts"] = (root / "files-route.ts").read_text(
            encoding="utf-8"
        )
        files["server/api/files/index.post.ts"] = (root / "files-index-route.ts").read_text(
            encoding="utf-8"
        )
    return files


def _is_platform_adapter(path: Path) -> bool:
    try:
        return ADAPTER_MARKER in path.read_text(encoding="utf-8")
    except OSError:
        return False


def install_file_adapter(
    repo_path: str,
    project_type: str,
    *,
    replace_local: bool = False,
) -> dict[str, list[str]]:
    written: list[str] = []
    skipped: list[str] = []
    backed: list[str] = []
    root = Path(repo_path)
    if replace_local:
        seen: set[Path] = set()
        candidates = [root / rel for rel in _LOCAL_FILE_ROUTES]
        for directory in (root / "server/api/files", root / "functions/api/files"):
            if directory.is_dir():
                candidates.extend(
                    path
                    for path in directory.rglob("*")
                    if path.suffix in {".ts", ".js"} and path.is_file()
                )
        for path in candidates:
            resolved = path.resolve()
            if resolved in seen or not path.is_file() or _is_platform_adapter(path):
                continue
            seen.add(resolved)
            dest = move_to_bak(root, path.relative_to(root).as_posix())
            backed.append(dest)
    for name, content in file_adapter_files(project_type).items():
        path = root / name
        if path.exists() and not replace_local and not _is_platform_adapter(path):
            skipped.append(name)
            continue
        path.parent.mkdir(parents=True, exist_ok=True)
        path.write_text(content, encoding="utf-8", newline="\n")
        written.append(name)
    return {"written": written, "backed_up": backed, "skipped": skipped}
