# #region AddDefgroupIngroup [C:3] [TYPE Module] [SEMANTICS migration,defgroup,ingroup]
# @defgroup Migration Add @defgroup/@ingroup — zero-risk additive operation.
# @BRIEF Inserts one line after each #region anchor. No renames. No deletions. Bottom-up insertion.
# @RATIONALE 97.9% of contracts lack @ingroup — the model's strongest pre-training DSA signal.
# @INVARIANT Anchor pairs untouched. @RELATION edges untouched. Business logic untouched.

import re, sys
from pathlib import Path

PATH_TO_DOMAIN = [
    ("frontend/src/lib/models/", "Models"), ("frontend/src/lib/components/ui/", "UI"),
    ("frontend/src/lib/components/translate/", "Translate"), ("frontend/src/lib/components/dashboard/", "Dashboard"),
    ("frontend/src/lib/components/llm/", "LLM"), ("frontend/src/lib/components/dataset-review/", "DatasetReview"),
    ("frontend/src/lib/components/settings/", "Settings"), ("frontend/src/lib/components/layout/", "Layout"),
    ("frontend/src/lib/components/assistant/", "Assistant"), ("frontend/src/lib/components/tasks/", "Tasks"),
    ("frontend/src/lib/components/", "Components"), ("frontend/src/lib/ui/", "UI"),
    ("frontend/src/lib/stores/", "Stores"), ("frontend/src/lib/api/", "ApiClient"),
    ("frontend/src/routes/", "Routes"), ("frontend/src/types/", "Types"),
    ("backend/src/api/routes/assistant/", "AssistantApi"), ("backend/src/api/routes/", "Api"),
    ("backend/src/core/task_manager/", "TaskManager"), ("backend/src/core/auth/", "Auth"),
    ("backend/src/core/migration/", "Migration"), ("backend/src/core/plugins/", "Plugin"),
    ("backend/src/core/", "Core"), ("backend/src/services/dataset_review/", "DatasetReview"),
    ("backend/src/services/", "Services"), ("backend/src/models/", "Models"),
    ("backend/src/schemas/", "Schemas"), ("backend/src/plugins/translate/", "Translate"),
    ("backend/src/plugins/llm_analysis/", "LLMAnalysis"), ("backend/src/plugins/git/", "Git"),
    ("backend/src/plugins/storage/", "Storage"), ("backend/src/plugins/", "Plugin"),
    ("backend/tests/", "Tests"),
]

SEMANTICS_TO_DOMAIN = {
    "auth": "Auth", "login": "Auth", "token": "Auth", "migration": "Migration",
    "dashboard": "Dashboard", "dataset": "Dataset", "translate": "Translate",
    "translation": "Translate", "llm": "LLM", "git": "Git", "storage": "Storage",
    "plugin": "Plugin", "task": "Tasks", "test": "Tests", "api": "Api", "ui": "UI",
    "users": "Users", "roles": "Roles", "settings": "Settings", "profile": "Profile",
    "reports": "Reports", "validation": "Validation", "backup": "Backup",
    "mapper": "Mapper", "debug": "Debug", "assistant": "Assistant", "admin": "Admin",
    "notification": "Notifications", "schedule": "Schedule", "logging": "Logging",
    "indexing": "Index", "curation": "Curator", "semantic": "Semantic",
    "screenshot": "Screenshot", "health": "Health",
}

ANCHOR_RE = re.compile(
    r'^(\s*(?:#|//|<!--)\s*#region\s+(?P<id>[^\s\[\(]+)\s*\[[^\]]+\][^\n]*)', re.MULTILINE)
INGROUP_RE = re.compile(r'@ingroup\s', re.MULTILINE)
DEFGROUP_RE = re.compile(r'@defgroup\s', re.MULTILINE)
SEMANTICS_RE = re.compile(r'@SEMANTICS\s+([^\n]+)')


def find_files(root):
    dirs = [root / d for d in ["backend/src", "frontend/src", "backend/tests"]]
    return sorted({f for d in dirs if d.exists() for f in d.rglob("*.py")} |
                  {f for d in dirs if d.exists() for f in d.rglob("*.svelte")} |
                  {f for d in dirs if d.exists() for f in d.rglob("*.svelte.ts")})


def infer_domain(fp, semantics):
    for kw in semantics:
        kw = kw.strip().lower()
        if kw in SEMANTICS_TO_DOMAIN:
            return SEMANTICS_TO_DOMAIN[kw]
    s = str(fp)
    for prefix, domain in PATH_TO_DOMAIN:
        if prefix in s:
            return domain
    return "Module"


def process(fp, dry_run=True):
    content = fp.read_text(encoding="utf-8")
    insertions = []  # (byte_position, text_to_insert)

    for m in ANCHOR_RE.finditer(content):
        anchor_line = m.group(0)
        cid = m.group("id")
        pos = m.end()  # right after anchor line

        # Skip checks
        if cid.startswith("_"):
            continue
        if "[C:1]" in anchor_line:
            continue
        if "tests" in str(fp).lower() or "__tests__" in str(fp):
            continue

        # Check nearby text for existing @ingroup/@defgroup
        nearby = content[pos:pos + 600]
        if INGROUP_RE.search(nearby) or DEFGROUP_RE.search(nearby):
            continue

        sem = SEMANTICS_RE.search(content[m.start():pos + 600])
        semantics = [s.strip() for s in sem.group(1).split(",")] if sem else []
        domain = infer_domain(fp, semantics)

        stripped = anchor_line.strip()
        if stripped.startswith("<!--"):
            prefix, suffix = "<!-- ", " -->"
        elif stripped.startswith("//"):
            prefix, suffix = "// ", ""
        else:
            prefix, suffix = "# ", ""

        is_mod = "[TYPE Module]" in anchor_line or "[TYPE Class]" in anchor_line
        line = f"\n{prefix}@defgroup {domain} Module group.{suffix}" if is_mod else f"\n{prefix}@ingroup {domain}{suffix}"
        insertions.append((pos, line))

    # Apply bottom-up
    new_content = content
    for pos, line in sorted(insertions, reverse=True):
        new_content = new_content[:pos] + line + new_content[pos:]

    if insertions and not dry_run:
        fp.write_text(new_content, encoding="utf-8")

    return {"file": str(fp), "added": len(insertions)}


def main():
    dry = "--apply" not in sys.argv
    root = Path.cwd()
    for a in sys.argv[1:]:
        if a.startswith("--root="):
            root = Path(a.split("=", 1)[1])
    print(f"=== @defgroup/@ingroup — {'DRY RUN' if dry else 'APPLY'} ===")
    files = find_files(root)
    total, results = 0, []
    for f in files:
        r = process(f, dry_run=dry)
        if r["added"]:
            results.append(r)
            total += r["added"]
    print(f"Files: {len(results)}  Insertions: {total}")
    if dry:
        print("Run with --apply.")

if __name__ == "__main__":
    main()
# #endregion AddDefgroupIngroup
