# retoor <retoor@molodetz.nl>

from .._shared import endpoint, field

GROUP = {
        "slug": "project-files",
        "title": "Project Filesystem",
        "intro": """
# Project Filesystem

Each project carries a full virtual filesystem - directories and files - so a project can hold a
complete software project. Reading is public (anyone can browse a project's tree); creating,
editing, uploading, moving and deleting require the project owner. Text files are editable inline;
binary files are uploaded and served from `/static/uploads/project_files/...`.

Paths are relative POSIX paths inside the project (for example `src/main.py`). Parent directories
are created automatically on write, upload and mkdir. Paths containing `..`, null bytes or empty
segments are rejected.

Every endpoint follows the shared [Conventions & Errors](/docs/conventions.html) (auth, content
negotiation, status codes); see [Authentication](/docs/authentication.html) for the four ways to
sign requests.
""",
        "endpoints": [
            endpoint(
                id="project-files-list",
                method="GET",
                path="/projects/{project_slug}/files",
                title="List a project's files",
                summary="Return the flat list of files and directories in a project.",
                auth="public",
                params=[
                    field(
                        "project_slug",
                        "path",
                        "string",
                        True,
                        "PROJECT_SLUG",
                        "Project slug or uid.",
                    )
                ],
                sample_response={
                    "project": {"uid": "PROJECT_UID", "slug": "PROJECT_SLUG"},
                    "files": [
                        {
                            "path": "src/main.py",
                            "name": "main.py",
                            "type": "file",
                            "is_binary": False,
                            "size": 42,
                        }
                    ],
                    "is_owner": False,
                },
            ),
            endpoint(
                id="project-files-raw",
                method="GET",
                path="/projects/{project_slug}/files/raw",
                title="Read a project file",
                summary="Return one file's metadata and (for text files) its content.",
                auth="public",
                params=[
                    field(
                        "project_slug",
                        "path",
                        "string",
                        True,
                        "PROJECT_SLUG",
                        "Project slug or uid.",
                    ),
                    field(
                        "path",
                        "query",
                        "string",
                        True,
                        "src/main.py",
                        "Relative file path inside the project.",
                    ),
                ],
                sample_response={
                    "path": "src/main.py",
                    "name": "main.py",
                    "type": "file",
                    "is_binary": False,
                    "mime_type": "text/plain",
                    "size": 42,
                    "url": None,
                    "content": "print('hello')\n",
                },
            ),
            endpoint(
                id="project-files-write",
                method="POST",
                path="/projects/{project_slug}/files/write",
                title="Write a text file",
                summary="Create or overwrite a text file; parent directories are created automatically.",
                auth="user",
                encoding="form",
                destructive=True,
                params=[
                    field(
                        "project_slug",
                        "path",
                        "string",
                        True,
                        "PROJECT_SLUG",
                        "Project slug or uid.",
                    ),
                    field(
                        "path",
                        "form",
                        "string",
                        True,
                        "src/main.py",
                        "Relative file path.",
                    ),
                    field(
                        "content",
                        "form",
                        "textarea",
                        True,
                        "print('hello')",
                        "Full file content (max 400000 chars).",
                    ),
                ],
                notes=["Owner only; non-owners get `403`. Invalid paths return `400`."],
                sample_response={
                    "ok": True,
                    "redirect": "/projects/PROJECT_SLUG/files",
                    "data": {"path": "src/main.py", "type": "file"},
                },
            ),
            endpoint(
                id="project-files-lines",
                method="GET",
                path="/projects/{project_slug}/files/lines",
                title="Read a line range",
                summary="Read a 1-indexed inclusive line range of a text file. Returns lines plus total_lines for targeting edits.",
                auth="public",
                params=[
                    field(
                        "project_slug",
                        "path",
                        "string",
                        True,
                        "PROJECT_SLUG",
                        "Project slug or uid.",
                    ),
                    field(
                        "path",
                        "query",
                        "string",
                        True,
                        "src/main.py",
                        "Relative file path.",
                    ),
                    field(
                        "start",
                        "query",
                        "integer",
                        False,
                        "1",
                        "First line, 1-indexed (default 1).",
                    ),
                    field(
                        "end",
                        "query",
                        "integer",
                        False,
                        "50",
                        "Last line inclusive; omit or -1 for end of file.",
                    ),
                ],
                notes=[
                    "Text files only; binary, directory, or missing paths return `404`."
                ],
                sample_response={
                    "path": "src/main.py",
                    "start": 1,
                    "end": 2,
                    "total_lines": 2,
                    "lines": ["import os", "print(os.getcwd())"],
                    "content": "import os\nprint(os.getcwd())",
                },
            ),
            endpoint(
                id="project-files-replace-lines",
                method="POST",
                path="/projects/{project_slug}/files/replace-lines",
                title="Replace a line range",
                summary="Replace lines start..end (inclusive) with new content; empty content deletes the range. Leaves the rest of the file untouched.",
                auth="user",
                encoding="form",
                destructive=True,
                params=[
                    field(
                        "project_slug",
                        "path",
                        "string",
                        True,
                        "PROJECT_SLUG",
                        "Project slug or uid.",
                    ),
                    field(
                        "path",
                        "form",
                        "string",
                        True,
                        "src/main.py",
                        "Relative file path.",
                    ),
                    field(
                        "start",
                        "form",
                        "integer",
                        True,
                        "10",
                        "First line to replace (1-indexed).",
                    ),
                    field(
                        "end",
                        "form",
                        "integer",
                        True,
                        "12",
                        "Last line to replace (inclusive).",
                    ),
                    field(
                        "content",
                        "form",
                        "textarea",
                        False,
                        "new code",
                        "Replacement text (empty deletes the range).",
                    ),
                ],
                notes=[
                    "Owner only. The preferred way to edit a large file; avoids rewriting the whole file."
                ],
                sample_response={
                    "ok": True,
                    "redirect": "/projects/PROJECT_SLUG/files",
                    "data": {"path": "src/main.py", "type": "file"},
                },
            ),
            endpoint(
                id="project-files-insert-lines",
                method="POST",
                path="/projects/{project_slug}/files/insert-lines",
                title="Insert lines",
                summary="Insert content before a 1-indexed line. Use at=1 to prepend and at=total_lines+1 to append.",
                auth="user",
                encoding="form",
                destructive=True,
                params=[
                    field(
                        "project_slug",
                        "path",
                        "string",
                        True,
                        "PROJECT_SLUG",
                        "Project slug or uid.",
                    ),
                    field(
                        "path",
                        "form",
                        "string",
                        True,
                        "src/main.py",
                        "Relative file path.",
                    ),
                    field(
                        "at",
                        "form",
                        "integer",
                        True,
                        "1",
                        "Insert before this 1-indexed line.",
                    ),
                    field(
                        "content",
                        "form",
                        "textarea",
                        True,
                        "# header",
                        "Text to insert.",
                    ),
                ],
                sample_response={
                    "ok": True,
                    "redirect": "/projects/PROJECT_SLUG/files",
                    "data": {"path": "src/main.py", "type": "file"},
                },
            ),
            endpoint(
                id="project-files-delete-lines",
                method="POST",
                path="/projects/{project_slug}/files/delete-lines",
                title="Delete a line range",
                summary="Delete lines start..end (inclusive) from a text file.",
                auth="user",
                encoding="form",
                destructive=True,
                params=[
                    field(
                        "project_slug",
                        "path",
                        "string",
                        True,
                        "PROJECT_SLUG",
                        "Project slug or uid.",
                    ),
                    field(
                        "path",
                        "form",
                        "string",
                        True,
                        "src/main.py",
                        "Relative file path.",
                    ),
                    field(
                        "start",
                        "form",
                        "integer",
                        True,
                        "5",
                        "First line to delete (1-indexed).",
                    ),
                    field(
                        "end",
                        "form",
                        "integer",
                        True,
                        "7",
                        "Last line to delete (inclusive).",
                    ),
                ],
                sample_response={
                    "ok": True,
                    "redirect": "/projects/PROJECT_SLUG/files",
                    "data": {"path": "src/main.py", "type": "file"},
                },
            ),
            endpoint(
                id="project-files-append",
                method="POST",
                path="/projects/{project_slug}/files/append",
                title="Append to a file",
                summary="Append content as new lines at the end of a text file; grow a large file across calls without resending it.",
                auth="user",
                encoding="form",
                destructive=True,
                params=[
                    field(
                        "project_slug",
                        "path",
                        "string",
                        True,
                        "PROJECT_SLUG",
                        "Project slug or uid.",
                    ),
                    field(
                        "path", "form", "string", True, "log.txt", "Relative file path."
                    ),
                    field(
                        "content",
                        "form",
                        "textarea",
                        True,
                        "next chunk",
                        "Text to append.",
                    ),
                ],
                sample_response={
                    "ok": True,
                    "redirect": "/projects/PROJECT_SLUG/files",
                    "data": {"path": "log.txt", "type": "file"},
                },
            ),
            endpoint(
                id="project-files-upload",
                method="POST",
                path="/projects/{project_slug}/files/upload",
                title="Upload a file into a project",
                summary="Upload a file into a directory (parents created); text decodes to an editable file, otherwise stored as binary.",
                auth="user",
                encoding="multipart",
                destructive=True,
                params=[
                    field(
                        "project_slug",
                        "path",
                        "string",
                        True,
                        "PROJECT_SLUG",
                        "Project slug or uid.",
                    ),
                    field("file", "form", "file", True, "", "The file to upload."),
                    field(
                        "path",
                        "form",
                        "string",
                        False,
                        "assets",
                        "Target directory, empty for the root.",
                    ),
                ],
                sample_response={
                    "ok": True,
                    "redirect": "/projects/PROJECT_SLUG/files",
                    "data": {
                        "path": "assets/logo.png",
                        "type": "file",
                        "is_binary": True,
                    },
                },
            ),
            endpoint(
                id="project-files-mkdir",
                method="POST",
                path="/projects/{project_slug}/files/mkdir",
                title="Create a directory",
                summary="Create a directory and any missing parents.",
                auth="user",
                encoding="form",
                destructive=True,
                params=[
                    field(
                        "project_slug",
                        "path",
                        "string",
                        True,
                        "PROJECT_SLUG",
                        "Project slug or uid.",
                    ),
                    field(
                        "path",
                        "form",
                        "string",
                        True,
                        "src/components",
                        "Relative directory path.",
                    ),
                ],
                sample_response={
                    "ok": True,
                    "redirect": "/projects/PROJECT_SLUG/files",
                    "data": {"path": "src/components", "type": "dir"},
                },
            ),
            endpoint(
                id="project-files-move",
                method="POST",
                path="/projects/{project_slug}/files/move",
                title="Move or rename",
                summary="Move or rename a file or directory (and its descendants).",
                auth="user",
                encoding="form",
                destructive=True,
                params=[
                    field(
                        "project_slug",
                        "path",
                        "string",
                        True,
                        "PROJECT_SLUG",
                        "Project slug or uid.",
                    ),
                    field(
                        "from_path",
                        "form",
                        "string",
                        True,
                        "src/old.py",
                        "Existing path.",
                    ),
                    field("to_path", "form", "string", True, "src/new.py", "New path."),
                ],
                sample_response={
                    "ok": True,
                    "redirect": "/projects/PROJECT_SLUG/files",
                    "data": {"path": "src/new.py"},
                },
            ),
            endpoint(
                id="project-files-delete",
                method="POST",
                path="/projects/{project_slug}/files/delete",
                title="Delete a file or directory",
                summary="Delete a file, or a directory and everything under it. Project owner or an administrator; soft-deleted (restorable from admin trash). Blocked while the project is read-only.",
                auth="user",
                encoding="form",
                destructive=True,
                params=[
                    field(
                        "project_slug",
                        "path",
                        "string",
                        True,
                        "PROJECT_SLUG",
                        "Project slug or uid.",
                    ),
                    field(
                        "path",
                        "form",
                        "string",
                        True,
                        "src/old.py",
                        "Relative path to delete.",
                    ),
                ],
                sample_response={
                    "ok": True,
                    "redirect": "/projects/PROJECT_SLUG/files",
                    "data": {"path": "src/old.py"},
                },
            ),
            endpoint(
                id="project-files-zip",
                method="POST",
                path="/projects/{project_slug}/files/zip",
                title="Queue a zip of files",
                summary="Archive the whole tree, or a subtree via the path query. Returns the job uid and status URL to poll with /zips/{uid}.",
                auth="public",
                params=[
                    field(
                        "project_slug",
                        "path",
                        "string",
                        True,
                        "PROJECT_SLUG",
                        "Project slug or uid.",
                    ),
                    field(
                        "path",
                        "query",
                        "string",
                        False,
                        "src",
                        "Relative file or directory to archive; empty for the whole project.",
                    ),
                ],
                sample_response={
                    "uid": "ZIP_JOB_UID",
                    "status_url": "/zips/ZIP_JOB_UID",
                },
            ),
        ],
}
