#!/usr/bin/env python3
"""odysseus-personal — shell wrapper for the personal-docs RAG index.

`data/personal_docs/` holds local files indexed into RAG so chat can
recall their content (`contacts.txt`, runbook fragments, etc.). This
CLI lists indexed directories + manages the index.

    odysseus-personal list                  # files currently in the index
    odysseus-personal dirs                  # tracked directory roots
    odysseus-personal add-dir DIR
    odysseus-personal remove-dir DIR
    odysseus-personal reload                # re-scan all dirs
    odysseus-personal exclude PATH          # mark a file as excluded
"""

from __future__ import annotations
import sys
import os, sys
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "_lib"))
from cli import quiet_logs, emit, fail, common_parser, run, REPO_ROOT as _REPO_ROOT
quiet_logs()

import argparse, json, logging, os, sys
from pathlib import Path

try:
    from src.personal_docs import PersonalDocsManager
    quiet_logs()
except ModuleNotFoundError as e:
    sys.stderr.write(f"error: {e}\nhint: run from repo root with venv active.\n")
    sys.exit(2)


_DATA_DIR = str(_REPO_ROOT / "data")
_mgr: PersonalDocsManager | None = None


def _manager() -> PersonalDocsManager:
    global _mgr
    if _mgr is None:
        _mgr = PersonalDocsManager(_DATA_DIR)
    return _mgr


def _file_rows(files):
    return [f for f in files or [] if isinstance(f, dict)]


def cmd_list(args):
    files = _file_rows(getattr(_manager(), "index", []) or [])
    out = [
        {"name": f.get("name"), "size": f.get("size"), "path": f.get("path", "")}
        for f in files
    ]
    emit(out[: args.limit], args)


def cmd_dirs(args):
    fn = getattr(_manager(), "get_indexed_directories", None)
    if fn is None:
        emit([], args)
        return
    emit(fn() or [], args)


def cmd_add_dir(args):
    fn = getattr(_manager(), "add_directory", None)
    if fn is None:
        fail("PersonalDocsManager has no add_directory method on this version")
    fn(args.directory)
    emit({"ok": True, "directory": args.directory}, args)


def cmd_remove_dir(args):
    fn = getattr(_manager(), "remove_directory", None)
    if fn is None:
        fail("PersonalDocsManager has no remove_directory method on this version")
    fn(args.directory)
    emit({"ok": True, "directory": args.directory}, args)


def cmd_reload(args):
    _manager().refresh_index()
    emit({"ok": True, "count": len(_manager().index)}, args)


def cmd_exclude(args):
    fn = getattr(_manager(), "exclude_file", None)
    if fn is None:
        fail("PersonalDocsManager has no exclude_file method on this version")
    fn(args.path)
    emit({"ok": True, "excluded": args.path}, args)


def _build_parser():
    common = argparse.ArgumentParser(add_help=False)
    common.add_argument("--pretty", action="store_true")
    p = argparse.ArgumentParser(prog="odysseus-personal", parents=[common])
    sub = p.add_subparsers(dest="cmd", required=True)

    pl = sub.add_parser("list", parents=[common])
    pl.add_argument("--limit", type=int, default=500)
    pl.set_defaults(func=cmd_list)

    pd = sub.add_parser("dirs", parents=[common])
    pd.set_defaults(func=cmd_dirs)

    pa = sub.add_parser("add-dir", parents=[common])
    pa.add_argument("directory")
    pa.set_defaults(func=cmd_add_dir)

    pr = sub.add_parser("remove-dir", parents=[common])
    pr.add_argument("directory")
    pr.set_defaults(func=cmd_remove_dir)

    prl = sub.add_parser("reload", parents=[common])
    prl.set_defaults(func=cmd_reload)

    pex = sub.add_parser("exclude", parents=[common])
    pex.add_argument("path")
    pex.set_defaults(func=cmd_exclude)

    return p


if __name__ == "__main__":
    sys.exit(run(_build_parser()))
