from __future__ import annotations

from pathlib import Path
from typing import Mapping, Optional

from .config import ROOT_CONFIG_FILENAME, ROOT_OVERRIDE_FILENAME, Config

ABOUT_CAR_BASENAME = "ABOUT_CAR.md"
ABOUT_CAR_REL_PATH = Path(".codex-autorunner") / ABOUT_CAR_BASENAME

# If this marker is present, codex-autorunner may safely refresh the file content.
ABOUT_CAR_GENERATED_MARKER = "<!-- CAR:AUTOGENERATED -->"


def _display_path(repo_root: Path, path: Path) -> str:
    try:
        return str(path.relative_to(repo_root))
    except ValueError:
        return str(path)


def build_about_car_markdown(
    *,
    repo_root: Path,
    todo_path: Path,
    progress_path: Path,
    opinions_path: Path,
    spec_path: Path,
    summary_path: Path,
    config_path: Optional[Path] = None,
) -> str:
    config_path = config_path or (repo_root / ".codex-autorunner" / "config.yml")
    root_config_path = repo_root / ROOT_CONFIG_FILENAME
    root_override_path = repo_root / ROOT_OVERRIDE_FILENAME
    todo_disp = _display_path(repo_root, todo_path)
    progress_disp = _display_path(repo_root, progress_path)
    opinions_disp = _display_path(repo_root, opinions_path)
    spec_disp = _display_path(repo_root, spec_path)
    summary_disp = _display_path(repo_root, summary_path)
    config_disp = _display_path(repo_root, config_path)
    root_config_disp = _display_path(repo_root, root_config_path)
    root_override_disp = _display_path(repo_root, root_override_path)

    return (
        f"{ABOUT_CAR_GENERATED_MARKER}\n"
        "# ABOUT_CAR — Codex Autorunner (CAR)\n\n"
        "You are running inside **Codex Autorunner (CAR)**.\n\n"
        "CAR uses a small set of markdown **work docs** as the control surface for long-horizon work. "
        "These docs live under the repo-local, gitignored `.codex-autorunner/` directory.\n\n"
        "## Work docs (canonical)\n"
        "- **TODO** — ordered checklist of high-level tasks: "
        f"`{todo_disp}`\n"
        "- **PROGRESS** — running notes / validation / context: "
        f"`{progress_disp}`\n"
        "- **OPINIONS** — constraints + style guidelines: "
        f"`{opinions_disp}`\n"
        "- **SPEC** — source-of-truth requirements and scope: "
        f"`{spec_disp}`\n"
        "- **SUMMARY** — user-facing report + external/user action items: "
        f"`{summary_disp}`\n\n"
        "## Critical rules\n"
        f'- When the user says **"add this to the TODOs"**, edit `{todo_disp}`.\n'
        "- Do **not** create new copies of TODO/PROGRESS/OPINIONS/SPEC/SUMMARY elsewhere in the repo.\n"
        "- Treat `.codex-autorunner/` as intentional project structure even though it is hidden/gitignored.\n\n"
        "## How CAR works (short)\n"
        "- `car run/once` repeatedly runs Codex non-interactively, feeding it the work docs (and the prior run tail).\n"
        "- `car serve` starts a local web UI. The **Terminal** tab launches the configured `codex` binary in a PTY.\n"
        f"- Repo config lives at `{config_disp}` (doc paths, codex args, server host/port).\n"
        f"- Root defaults live at `{root_config_disp}` with optional `{root_override_disp}` overrides.\n"
    )


def ensure_about_car_file_for_repo(
    repo_root: Path,
    *,
    doc_paths: Mapping[str, Path],
    force: bool = False,
) -> Path:
    """
    Ensure `.codex-autorunner/ABOUT_CAR.md` exists for this repo.

    If the file already exists and contains the generated marker, it may be refreshed
    (unless force=False and content already matches).
    """
    path = repo_root / ABOUT_CAR_REL_PATH
    path.parent.mkdir(parents=True, exist_ok=True)

    content = build_about_car_markdown(
        repo_root=repo_root,
        todo_path=doc_paths["todo"],
        progress_path=doc_paths["progress"],
        opinions_path=doc_paths["opinions"],
        spec_path=doc_paths["spec"],
        summary_path=doc_paths["summary"],
        config_path=repo_root / ".codex-autorunner" / "config.yml",
    )
    if content and not content.endswith("\n"):
        content += "\n"

    if path.exists() and not force:
        try:
            existing = path.read_text(encoding="utf-8")
        except OSError:
            existing = ""
        # Only overwrite if it's our generated file (marker) and content changed.
        if ABOUT_CAR_GENERATED_MARKER not in existing:
            return path
        if existing == content:
            return path

    path.write_text(content, encoding="utf-8")
    return path


def ensure_about_car_file(config: Config, *, force: bool = False) -> Path:
    """Config-aware wrapper that uses configured doc paths."""
    repo_root = config.root
    docs = {
        "todo": config.doc_path("todo"),
        "progress": config.doc_path("progress"),
        "opinions": config.doc_path("opinions"),
        "spec": config.doc_path("spec"),
        "summary": config.doc_path("summary"),
    }
    return ensure_about_car_file_for_repo(repo_root, doc_paths=docs, force=force)
