"""
snapshot_project.py
-------------------
Run this from the ROOT of your Django project (same folder as manage.py):

    python snapshot_project.py

It produces a single file  →  project_snapshot.txt

Paste that file's contents into Claude for a complete picture of your
codebase with zero secrets exposed.

Safe to run: reads only Python/HTML/CSS/JS source files.
Skips: .env, secrets, media, migrations, __pycache__, venv, staticfiles.
"""

import os
import sys

# ── Configuration ────────────────────────────────────────────────────────────

OUTPUT_FILE = "project_snapshot.txt"

# Folders to skip entirely
SKIP_DIRS = {
    "venv", ".venv", "env", "__pycache__", ".git",
    "node_modules", "staticfiles", "media", "logs",
    "migrations",          # skip migration files — too noisy, not useful
    ".mypy_cache", ".pytest_cache",
}

# File extensions to include
INCLUDE_EXTS = {".py", ".html", ".css", ".js", ".json", ".txt", ".md", ".cfg", ".ini", ".toml"}

# Files to skip by name (secrets / noise)
SKIP_FILES = {
    ".env", ".env.local", ".env.production",
    "secrets.py", "local_settings.py",
    "db.sqlite3", "*.pyc",
}

# Keys in settings.py whose VALUES we redact
REDACT_KEYS = {
    "SECRET_KEY", "PASSWORD", "DATABASE_URL", "EMAIL_HOST_PASSWORD",
    "AWS_SECRET", "API_KEY", "TOKEN", "SENDGRID", "TWILIO",
}

# Max bytes to read per file (skip giant files)
MAX_FILE_BYTES = 60_000

# Django apps — we dump these fully
DJANGO_APPS = [
    "academics", "api", "backend", "communication", "core",
    "finance", "parents", "reports", "scripts", "staff",
    "students", "sync", "templates",
]

# ── Helpers ──────────────────────────────────────────────────────────────────

def should_skip_dir(name):
    return name in SKIP_DIRS or name.startswith(".")

def should_skip_file(name):
    if name in SKIP_FILES:
        return True
    if any(name.endswith(ext) for ext in [".pyc", ".pyo", ".pyd"]):
        return True
    return False

def redact_settings(content):
    """Replace secret values in settings files with [REDACTED]."""
    lines = []
    for line in content.splitlines():
        upper = line.upper()
        if any(k in upper for k in REDACT_KEYS) and "=" in line:
            key_part = line.split("=")[0]
            lines.append(f"{key_part} = '[REDACTED]'")
        else:
            lines.append(line)
    return "\n".join(lines)

def read_file(path):
    try:
        size = os.path.getsize(path)
        if size > MAX_FILE_BYTES:
            return f"[FILE TOO LARGE — {size:,} bytes — skipped]"
        with open(path, "r", encoding="utf-8", errors="replace") as f:
            content = f.read()
        if "settings" in os.path.basename(path).lower():
            content = redact_settings(content)
        return content
    except Exception as e:
        return f"[ERROR READING FILE: {e}]"

def walk_app(app_dir, out):
    """Walk a single Django app directory and write all relevant files."""
    for root, dirs, files in os.walk(app_dir):
        # Prune skip dirs in-place
        dirs[:] = [d for d in sorted(dirs) if not should_skip_dir(d)]
        for fname in sorted(files):
            if should_skip_file(fname):
                continue
            ext = os.path.splitext(fname)[1].lower()
            if ext not in INCLUDE_EXTS:
                continue
            fpath = os.path.join(root, fname)
            rel = os.path.relpath(fpath)
            content = read_file(fpath)
            out.append(f"\n{'='*70}")
            out.append(f"FILE: {rel}")
            out.append('='*70)
            out.append(content)

# ── Main ─────────────────────────────────────────────────────────────────────

def main():
    cwd = os.getcwd()
    if not os.path.exists(os.path.join(cwd, "manage.py")):
        print("ERROR: Run this script from the Django project root (where manage.py lives).")
        sys.exit(1)

    print("Scanning project…")
    out = []

    # ── Header ────────────────────────────────────────────────────────────
    out.append("RAPHA-BETHEL BNPS — PROJECT SNAPSHOT")
    out.append(f"Generated from: {cwd}")
    out.append("")

    # ── Directory tree (top level only) ──────────────────────────────────
    out.append("=" * 70)
    out.append("TOP-LEVEL DIRECTORY STRUCTURE")
    out.append("=" * 70)
    try:
        entries = sorted(os.listdir(cwd))
        for e in entries:
            full = os.path.join(cwd, e)
            kind = "DIR " if os.path.isdir(full) else "FILE"
            out.append(f"  {kind}  {e}")
    except Exception as e:
        out.append(f"[ERROR: {e}]")

    # ── manage.py ────────────────────────────────────────────────────────
    manage = os.path.join(cwd, "manage.py")
    if os.path.exists(manage):
        out.append("\n" + "="*70)
        out.append("FILE: manage.py")
        out.append("="*70)
        out.append(read_file(manage))

    # ── requirements / dependencies ───────────────────────────────────────
    for req in ["requirements.txt", "requirements/base.txt",
                "requirements/prod.txt", "Pipfile", "pyproject.toml"]:
        rpath = os.path.join(cwd, req)
        if os.path.exists(rpath):
            out.append("\n" + "="*70)
            out.append(f"FILE: {req}")
            out.append("="*70)
            out.append(read_file(rpath))

    # ── Each Django app ───────────────────────────────────────────────────
    for app in DJANGO_APPS:
        app_path = os.path.join(cwd, app)
        if os.path.isdir(app_path):
            out.append(f"\n\n{'#'*70}")
            out.append(f"# APP: {app.upper()}")
            out.append(f"{'#'*70}")
            walk_app(app_path, out)
        else:
            out.append(f"\n[APP NOT FOUND: {app}]")

    # ── Any top-level .py files not already captured ───────────────────
    out.append(f"\n\n{'#'*70}")
    out.append("# ROOT-LEVEL PYTHON FILES")
    out.append(f"{'#'*70}")
    for fname in sorted(os.listdir(cwd)):
        if fname.endswith(".py") and fname != "manage.py" and not should_skip_file(fname):
            fpath = os.path.join(cwd, fname)
            if os.path.isfile(fpath):
                out.append(f"\n{'='*70}")
                out.append(f"FILE: {fname}")
                out.append("="*70)
                out.append(read_file(fpath))

    # ── Write output ──────────────────────────────────────────────────────
    full_output = "\n".join(out)
    with open(OUTPUT_FILE, "w", encoding="utf-8") as f:
        f.write(full_output)

    size_kb = os.path.getsize(OUTPUT_FILE) / 1024
    print(f"\nDone. Output written to: {OUTPUT_FILE}")
    print(f"File size: {size_kb:.1f} KB")
    print("")
    print("Next steps:")
    print("  1. Open project_snapshot.txt and check nothing sensitive slipped through.")
    print("  2. Paste its full contents into Claude.")
    print("  3. Claude will give you exact, file-specific integration code.")
    print("")
    if size_kb > 400:
        print("NOTE: File is large. If Claude's context fills up, you can split it:")
        print("  - Paste just the 'academics' and 'students' sections first.")
        print("  - Then paste 'reports', 'backend', and 'templates' in a follow-up.")

if __name__ == "__main__":
    main()
