"""`okstra task-list` 의 프로젝션 — 프로젝트에 등록된 task 목록.

이 코드는 원래 `src/commands/inspect/task-list.mts` 의 문자열 리터럴 안에 있었다.
docs/coding-rules.md R1(다른 언어 소스를 문자열에 담지 않는다) 위반이었고, 그래서
검사 도구도 테스트도 닿지 않았다. 로직은 그대로 옮겼다 — 이 모듈은 새 동작을
만들지 않는다.
"""
from __future__ import annotations

import argparse
import json
import sys
from pathlib import Path

from okstra_project import (
    ResolverError,
    list_project_tasks,
    read_latest_task,
    resolve_project_root,
)

from .fixed_text import line


def render_text(payload: dict) -> str:
    """모델용 고정 텍스트 투영. 줄 형식은 `fixed_text.line` 이 단일 기준점이다."""
    parts = ["# Okstra Task List\n\n", line("Task count", len(payload["tasks"]))]
    for task in payload["tasks"]:
        parts.extend((
            "\n## Task\n\n",
            line("Task key", task.get("taskKey")),
            line("Task type", task.get("taskType")),
            line("Task group", task.get("taskGroup")),
            line("Title", task.get("title") or task.get("taskTitle")),
            line("Latest run status", task.get("latestRunStatus")),
            line("Work status", task["workStatus"]) if task.get("workStatus") else "",
            line("Direct work record", task["latestWorkRecordPath"]) if task.get("latestWorkRecordPath") else "",
            line("Updated at", task.get("updatedAt")),
        ))
    return "".join(parts)


def render_resolve_failure(reason: str) -> str:
    return (
        "Okstra task list\n"
        + line("Status", "error")
        + line("Failure stage", "resolve")
        + line("Failure reason", reason)
    )


def collect(
    project_root: Path,
    *,
    task_type: str | None = None,
    latest_run_status: str | None = None,
    task_group: str | None = None,
    limit: int | None = None,
) -> dict:
    return {
        "ok": True,
        "projectRoot": str(project_root),
        "tasks": list_project_tasks(
            project_root,
            task_type=task_type,
            latest_run_status=latest_run_status,
            task_group=task_group,
            limit=limit,
        ),
        "latest": read_latest_task(project_root),
    }


_CLI_EPILOG = r"""Usage:
  okstra task-list                            Resolve PROJECT_ROOT from cwd, list tasks
  okstra task-list --cwd <dir>                Start resolution from <dir> instead of cwd
  okstra task-list --project <dir>            Use <dir> directly as PROJECT_ROOT
  okstra task-list --task-type <type>         Filter by taskType
  okstra task-list --latest-run-status <s>    Filter by latestRunStatus
  okstra task-list --task-group <group>       Filter by taskGroup
  okstra task-list --limit <N>                Keep the first N (catalog is updatedAt desc)
  okstra task-list --text                     Emit fixed task identity fields for model use

Output: default emits JSON { ok, projectRoot, tasks: [...], latest: {...}|null }.
--text emits fixed task key/type/group/title/latest-status/updated fields.
Filters are AND-combined and all optional.
"""
_CLI_DESCRIPTION = "List okstra tasks registered in this project."


def main(argv: list[str] | None = None) -> int:
    parser = argparse.ArgumentParser(
        description=_CLI_DESCRIPTION,
        epilog=_CLI_EPILOG,
        formatter_class=argparse.RawDescriptionHelpFormatter,
        prog="okstra task-list")
    parser.add_argument("--project-root", "--project", default="",
                        help="use this directory as PROJECT_ROOT")
    parser.add_argument("--cwd", default=".",
                        help="resolve PROJECT_ROOT starting from here")
    parser.add_argument("--task-type", default="", help="filter by taskType")
    parser.add_argument("--latest-run-status", default="",
                        help="filter by latestRunStatus")
    parser.add_argument("--task-group", default="", help="filter by taskGroup")
    parser.add_argument("--limit", default="",
                        help="keep the first N (the catalog is updatedAt desc)")
    mode = parser.add_mutually_exclusive_group()
    mode.add_argument("--json", dest="output_mode", action="store_const",
                      const="json", default="json", help="emit JSON (default)")
    mode.add_argument("--text", dest="output_mode", action="store_const",
                      const="text", help="emit fixed task identity fields")
    args = parser.parse_args(argv)

    try:
        resolved = resolve_project_root(
            explicit_root=args.project_root, cwd=args.cwd
        )
    except ResolverError as exc:
        if args.output_mode == "text":
            print(render_resolve_failure(str(exc)), end="")
        else:
            print(json.dumps({"ok": False, "stage": "resolve", "reason": str(exc)}))
        return 2

    payload = collect(
        Path(resolved),
        task_type=args.task_type or None,
        latest_run_status=args.latest_run_status or None,
        task_group=args.task_group or None,
        limit=int(args.limit) if args.limit else None,
    )
    if args.output_mode == "text":
        print(render_text(payload), end="")
    else:
        print(json.dumps(payload, default=str))
    return 0


if __name__ == "__main__":
    raise SystemExit(main())
