#!/usr/bin/env python3
from __future__ import annotations

import argparse
import os
import re
import sys
from pathlib import Path


SECTION_RE = re.compile(r"^#{2,4}\s+(.+)$")


def find_vault_root(start: str, marker: str | None = None) -> Path:
    """Vault ルート探索。`.obsidian/` の存在で判定する。
    marker を指定すると、ディレクトリ名一致でも探索する（後方互換のフォールバック）。
    """
    path = Path(start).resolve()
    while True:
        if (path / ".obsidian").is_dir():
            return path
        if marker and path.name == marker:
            return path
        if path.parent == path:
            label = marker or ".obsidian/"
            raise RuntimeError(f"Vault root ({label}) が見つかりません: {start}")
        path = path.parent


VAULT_ROOT = find_vault_root(os.path.dirname(os.path.abspath(__file__)))
BRAIN_ROOT = VAULT_ROOT / "Brain"


def resolve_path(raw: str) -> Path:
    path = Path(raw)
    if path.is_absolute():
        return path.resolve()
    return (VAULT_ROOT / path).resolve()


def ensure_brain_path(path: Path, role: str) -> None:
    if not path.exists():
        raise FileNotFoundError(f"{role} が見つかりません: {path}")
    if BRAIN_ROOT.resolve() not in path.parents:
        raise ValueError(f"{role} は Brain 配下である必要があります: {path}")


def build_appended_content(content: str, section: str, note_title: str, summary: str) -> str:
    if f"[[{note_title}]]" in content:
        raise ValueError(f"このノートはすでに MOC に存在します: [[{note_title}]]")

    lines = content.splitlines(keepends=True)
    section_line_index = None
    next_section_line_index = len(lines)

    for idx, line in enumerate(lines):
        match = SECTION_RE.match(line.strip("\n"))
        if not match:
            continue
        heading = match.group(1).strip()
        if section_line_index is None and heading == section:
            section_line_index = idx
            continue
        if section_line_index is not None:
            next_section_line_index = idx
            break

    if section_line_index is None:
        raise ValueError(f"指定セクションが見つかりません: {section}")

    bullet = f"- [[{note_title}]]\n"

    insert_at = next_section_line_index
    while insert_at > section_line_index + 1 and lines[insert_at - 1].strip() == "":
        insert_at -= 1

    new_lines = lines[:insert_at] + [bullet, "\n"] + lines[insert_at:]
    return "".join(new_lines)


def main() -> None:
    parser = argparse.ArgumentParser(description="既存 MOC の指定セクションへノートを追記する。")
    parser.add_argument("--moc", required=True, help="対象 MOC のパス")
    parser.add_argument("--section", required=True, help="追記先の見出し名（## を除く）")
    parser.add_argument("--note", required=True, help="追加するノートタイトル")
    parser.add_argument("--summary", default="", help="短い文脈説明")
    parser.add_argument("--dry-run", action="store_true", help="書き込まず差分だけ確認する")
    args = parser.parse_args()

    moc_path = resolve_path(args.moc)
    if not moc_path.exists():
        raise FileNotFoundError(f"MOC が見つかりません: {moc_path}")

    content = moc_path.read_text(encoding="utf-8")
    new_content = build_appended_content(
        content=content,
        section=args.section,
        note_title=args.note,
        summary=args.summary,
    )

    if args.dry_run:
        print(f"OK: {moc_path}")
        print(f"SECTION: {args.section}")
        bullet = f"- [[{args.note}]]" + (f"：{args.summary.strip()}" if args.summary.strip() else "")
        print(bullet.rstrip())
        return

    moc_path.write_text(new_content, encoding="utf-8")
    print(f"✅ 追記完了: {moc_path}")
    print(f"section={args.section}")
    bullet = f"- [[{args.note}]]" + (f"：{args.summary.strip()}" if args.summary.strip() else "")
    print(f"entry={bullet.rstrip()}")


if __name__ == "__main__":
    try:
        main()
    except Exception as exc:
        print(f"ERROR: {exc}", file=sys.stderr)
        sys.exit(1)
