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

import argparse
import importlib.util
import os
import sys
from pathlib import Path


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"
MOC_ROOT = BRAIN_ROOT / "MOC"


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


def load_module(path: Path, module_name: str):
    spec = importlib.util.spec_from_file_location(module_name, path)
    module = importlib.util.module_from_spec(spec)
    assert spec.loader is not None
    spec.loader.exec_module(module)
    return module


APPEND_MODULE = load_module(Path(__file__).with_name("append_note_to_moc.py"), "append_note_to_moc")
LINK_MODULE = load_module(Path(__file__).with_name("link_moc_to_root.py"), "link_moc_to_root")


def detect_child_kind(child_path: Path) -> str:
    if MOC_ROOT in child_path.parents:
        return "moc"
    if BRAIN_ROOT in child_path.parents:
        return "note"
    raise ValueError(f"追加対象は Brain 配下である必要があります: {child_path}")


def attach_note(target_path: Path, child_path: Path, section: str, summary: str, dry_run: bool) -> None:
    APPEND_MODULE.ensure_brain_path(child_path, "追加対象ノート")
    target_content = target_path.read_text(encoding="utf-8")
    target_frontmatter, _ = LINK_MODULE.split_frontmatter(target_content)
    target_title = LINK_MODULE.extract_title(target_content, target_path)
    target_moc_type = LINK_MODULE.extract_moc_type(target_frontmatter)
    if target_moc_type == "root":
        raise ValueError(
            "通常ノートを root MOC に直接追加してはいけません。"
            f" `[[{target_title}]]` から辿れる下位 MOC を選び、そちらへ追加してください。"
        )
    target_title = child_path.stem
    content = target_content
    new_content = APPEND_MODULE.build_appended_content(
        content=content,
        section=section,
        note_title=target_title,
        summary=summary,
    )

    if dry_run:
        print("MODE: note")
        print(f"TARGET: {target_path}")
        print(f"CHILD: {child_path}")
        print(f"ENTRY: - [[{target_title}]]")
        return

    target_path.write_text(new_content, encoding="utf-8")
    print(f"✅ MOC 追記完了: {target_path}")
    print(f"mode=note")
    print(f"entry=- [[{target_title}]]")


def attach_moc(
    target_path: Path,
    child_path: Path,
    section: str,
    summary: str,
    dry_run: bool,
    sync_up_link: bool,
    force_up_link: bool,
) -> None:
    LINK_MODULE.ensure_moc_path(target_path, "root MOC")
    LINK_MODULE.ensure_moc_path(child_path, "子 MOC")

    root_content = target_path.read_text(encoding="utf-8")
    child_content = child_path.read_text(encoding="utf-8")
    root_frontmatter, _ = LINK_MODULE.split_frontmatter(root_content)
    child_frontmatter, _ = LINK_MODULE.split_frontmatter(child_content)
    root_title = LINK_MODULE.extract_title(root_content, target_path)
    child_title = LINK_MODULE.extract_title(child_content, child_path)
    root_moc_type = LINK_MODULE.extract_moc_type(root_frontmatter)
    child_moc_type = LINK_MODULE.extract_moc_type(child_frontmatter)

    if root_moc_type != "root":
        raise ValueError(f"追加先は root MOC である必要があります: {root_title} ({root_moc_type})")
    if child_moc_type == "root" and root_title == child_title:
        raise ValueError("同じ root MOC を自分自身に追加することはできません。")

    new_root_content = LINK_MODULE.build_root_entry(
        root_content,
        section,
        child_title,
        summary,
    )

    up_status = "skipped"
    new_child_content = child_content
    if sync_up_link:
        new_child_content, up_status = LINK_MODULE.sync_up_link(
            child_content,
            root_title,
            force=force_up_link,
        )

    if dry_run:
        print("MODE: moc")
        print(f"TARGET: {target_path}")
        print(f"CHILD: {child_path}")
        print(f"ENTRY: - [[{child_title}]]")
        print(f"UP_LINK: {up_status}")
        return

    target_path.write_text(new_root_content, encoding="utf-8")
    if sync_up_link and new_child_content != child_content:
        child_path.write_text(new_child_content, encoding="utf-8")
    print(f"✅ root 追記完了: {target_path}")
    print("mode=moc")
    print(f"entry=- [[{child_title}]]")
    if sync_up_link:
        print(f"✅ Up リンク同期: {child_path}")
        print(f"up_link={up_status}")


def main() -> None:
    parser = argparse.ArgumentParser(description="追加対象がノートか MOC かを判定し、適切な MOC 追加処理へ振り分ける。")
    parser.add_argument("--target", required=True, help="追加先の MOC / root MOC パス")
    parser.add_argument("--child", required=True, help="追加するノートまたは子 MOC のパス")
    parser.add_argument("--section", required=True, help="追加先の見出し名（## を除く）")
    parser.add_argument("--summary", default="", help="追加理由の短い文脈説明")
    parser.add_argument("--sync-up-link", action="store_true", help="追加対象が MOC のとき、Up リンクを target に同期する")
    parser.add_argument("--force-up-link", action="store_true", help="追加対象が MOC のとき、既存の Up リンクが別でも置き換える")
    parser.add_argument("--dry-run", action="store_true", help="書き込まず変更内容だけ確認する")
    args = parser.parse_args()

    target_path = resolve_path(args.target)
    child_path = resolve_path(args.child)

    if not target_path.exists():
        raise FileNotFoundError(f"追加先 MOC が見つかりません: {target_path}")

    kind = detect_child_kind(child_path)
    if kind == "note":
        attach_note(target_path, child_path, args.section, args.summary, args.dry_run)
        return

    attach_moc(
        target_path,
        child_path,
        args.section,
        args.summary,
        args.dry_run,
        args.sync_up_link,
        args.force_up_link,
    )


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